]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/shipeditordlg.cpp
Initial revision
[taylor/freespace2.git] / src / fred2 / shipeditordlg.cpp
1 /*
2  * $Logfile: /Freespace2/code/fred2/ShipEditorDlg.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Single ship editing dialog
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:08  root
11  * Initial revision
12  *
13  * 
14  * 8     8/18/99 1:32p Andsager
15  * Mark Vasudan wingmen as such.
16  * 
17  * 7     8/18/99 1:12p Andsager
18  * Allow ships to be assigned Vasudan persona (wingman 6)
19  * 
20  * 6     8/16/99 10:52p Andsager
21  * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
22  * 
23  * 5     8/11/99 9:27a Andsager
24  * Fix compile warning.
25  * 
26  * 4     5/20/99 6:59p Dave
27  * Added alternate type names for ships. Changed swarm missile table
28  * entries.
29  * 
30  * 3     2/11/99 2:15p Andsager
31  * Add ship explosion modification to FRED
32  * 
33  * 2     10/07/98 6:28p Dave
34  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
35  * Fred. Globalized mission and campaign file extensions. Removed Silent
36  * Threat specific code.
37  * 
38  * 1     10/07/98 3:02p Dave
39  * 
40  * 1     10/07/98 3:00p Dave
41  * 
42  * 157   6/16/98 10:17a Hoffoss
43  * Fixed define that was backwards and no one caught before release (ya,
44  * great testing..)
45  * 
46  * 156   5/23/98 3:33p Hoffoss
47  * Removed unused code in reinforcements editor and make ships.tbl button
48  * in ship editor disappear in release build.
49  * 
50  * 155   5/21/98 12:58a Hoffoss
51  * Fixed warnings optimized build turned up.
52  * 
53  * 154   4/28/98 2:13p Hoffoss
54  * Added code to help keep invalid player ship types from existing in
55  * mission.
56  * 
57  * 153   4/24/98 2:57p Jim
58  * Fixed typo in code.
59  * 
60  * 152   4/22/98 11:55a Hoffoss
61  * Fixed bug with ship editor's hide cue button when sexp help is on at
62  * startup.
63  * 
64  * 151   4/16/98 5:59p Duncan
65  * Fixed bad assumption, apparently.
66  * 
67  * 150   4/07/98 9:42a Allender
68  * put in persona combo box into ship editor.  Removed code to assign
69  * personas based on message
70  * 
71  * 149   3/30/98 1:15p Hoffoss
72  * Fixed bug with arrival/departure cue window size calculation.  Wasn't
73  * working anymore after my changes to dialog initing at startup.
74  * 
75  * 148   3/27/98 12:02p Sandeep
76  * 
77  * 147   3/25/98 4:14p Hoffoss
78  * Split ship editor up into ship editor and a misc dialog, which tracks
79  * flags and such.
80  * 
81  * 146   3/21/98 7:36p Lawrance
82  * Move jump nodes to own lib.
83  * 
84  * 145   3/16/98 8:27p Allender
85  * Fred support for two new AI flags -- kamikaze and no dynamic goals.
86  * 
87  * 144   3/10/98 6:11p Hoffoss
88  * Added jump node renaming abilities to Fred.
89  * 
90  * 143   3/09/98 4:30p Allender
91  * multiplayer secondary weapon changes.  red-alert and cargo-known-delay
92  * sexpressions.  Add time cargo revealed to ship structure
93  * 
94  * 142   2/22/98 1:21a Hoffoss
95  * Disabled weapon editor if mutliple ship types marked.
96  * 
97  * 141   2/17/98 12:07p Hoffoss
98  * Changed over to using SF_CARGO_REVEALED in fred.
99  * 
100  * 140   2/17/98 11:42a Hoffoss
101  * Added support for hidden from sensors condition.
102  * 
103  * 139   2/13/98 2:42p Duncan
104  * Fixed bug, moved line down where it needs to be because
105  * pre-initializations need to be done first.
106  * 
107  * 138   2/10/98 1:42p Allender
108  * allow > MAX_ESCORT_SHIPS to be marked as escort ships
109  * 
110  * 137   2/06/98 2:54p Hoffoss
111  * Fixed some bugs in dialog init, and cleared up some of the confusion
112  * about how it works by renaming some variables and adding comments.
113  * 
114  * 136   2/06/98 10:48a Hoffoss
115  * Fixed bug with not being able to make ships players in multi mode
116  * missions.
117  * 
118  * 135   2/04/98 4:32p Allender
119  * support for multiple briefings and debriefings.  Changes to mission
120  * type (now a bitfield).  Bitfield defs for multiplayer modes
121  * 
122  * 134   1/29/98 5:14p Hoffoss
123  * Added support for a SF_INVULNERABLE ship flag in Fred.
124  * 
125  * 133   1/12/98 10:41a Allender
126  * fixed minor bug with ship editor and ignore orders dialog
127  * 
128  * 132   12/05/97 4:07p Hoffoss
129  * Changed code to allow WHO_FROM type ship sources to only show flyable
130  * ships in list.
131  * 
132  * 131   11/24/97 2:31p Allender
133  * allow ignore orders dialog to be active for players
134  * 
135  * 130   11/24/97 9:07a Allender
136  * ignore orders dialog should function as multi-edit now
137  * 
138  * 129   11/22/97 4:17p Allender
139  * first pass of making ignore orders dialog multi edit
140  * 
141  * 128   11/13/97 4:14p Allender
142  * automatic assignment of hotkeys for starting wings.  Appripriate
143  * warnings when they are incorrectly used.  hotkeys correctly assigned to
144  * ships/wing arriving after mission start
145  * 
146  * 127   11/11/97 3:32p Johnson
147  * allender:  Combo boxes need to have lists initialized before setting
148  * internal class variable for arrival/depature targets
149  * 
150  * 126   11/11/97 2:13p Allender
151  * docking bay support for Fred and Freespace.  Added hook to ai code for
152  * arrival/departure from dock bays.  Fred support now sufficient.
153  * 
154  * 125   11/10/97 10:13p Allender
155  * added departure anchor to Fred and Freespace in preparation for using
156  * docking bays.  Functional in Fred, not in FreeSpace.
157  * 
158  * 124   10/21/97 4:49p Allender
159  * added flags to Fred and FreeSpace to forgo warp effect (toggle in ship
160  * editor in Fred)
161  * 
162  * 123   10/14/97 5:33p Hoffoss
163  * Added Fred support (and fsm support) for the no_arrival_music flags in
164  * ships and wings.
165  * 
166  * 122   9/18/97 10:49a Allender
167  * increment/decrement Player_start variable when making a ship a player
168  * start
169  * 
170  * 121   9/17/97 5:43p Hoffoss
171  * Added Fred support for new player start information.
172  * 
173  * 120   9/16/97 9:41p Hoffoss
174  * Changed Fred code around to stop using Parse_player structure for
175  * player information, and use actual ships instead.
176  * 
177  * 119   9/15/97 2:35p Hoffoss
178  * Fixed bug in Fred where a player ship and normal ship both marked
179  * clobbered each other's ship type in ship editor dialog.
180  * 
181  * 118   9/09/97 10:29a Hoffoss
182  * Added support for neutral team, and fixed changes made to how team is
183  * used in ship structure.
184  * 
185  * 117   9/09/97 9:27a Hoffoss
186  * Removed #Jason Hoffoss# comments from code.  Code is already set up to
187  * handle the situation properly.
188  * 
189  * 116   9/06/97 2:13p Mike
190  * Replace support for TEAM_NEUTRAL
191  * 
192  * 115   9/04/97 5:35p Hoffoss
193  * Fixed arrival distance stuff.
194  * 
195  * 114   9/04/97 5:04p Johnson
196  * Fixed bug with arrival target distance checking.
197  * 
198  * 113   9/04/97 4:31p Hoffoss
199  * Fixed bug: Changed ship editor to not touch wing info (arrival or
200  * departure cues) to avoid conflicts with wing editor's changes.
201  * 
202  * 112   8/30/97 9:52p Hoffoss
203  * Implemented arrival location, distance, and anchor in Fred.
204  * 
205  * 111   8/28/97 8:56a Hoffoss
206  * Added more checking to sexp error checker, fixed some bugs.
207  * 
208  * 110   8/25/97 5:56p Hoffoss
209  * Added multiple asteroid field support, loading and saving of asteroid
210  * fields, and ship score field to Fred.
211  * 
212  * 109   8/22/97 4:16p Hoffoss
213  * added support for arrival and departure info in ship editor using
214  * wing's info if editing marked ships in a wing instead of using ship's.
215  * 
216  * 108   8/21/97 11:37p Hoffoss
217  * Fixed bug: when renaming a ship that is a reinforcement, an extra
218  * instance of it is added to the reinforcement list.
219  * 
220  * 107   8/20/97 6:53p Hoffoss
221  * Implemented escort flag support in Fred.
222  * 
223  * 106   8/19/97 2:53p Hoffoss
224  * Fixed bug where multiple ships editing doesn't change players.
225  * 
226  * 105   8/19/97 1:44p Hoffoss
227  * Fixed bug with updating too quickly (i.e. via prev and next buttons).
228  *
229  * $NoKeywords: $
230  */
231
232 #include "stdafx.h"
233 #include "fred.h"
234 #include "freddoc.h"
235 #include "fredview.h"
236 #include "mainfrm.h"
237 #include "3d.h"
238 #include "physics.h"
239 #include "editor.h"
240 #include "ailocal.h"
241 #include "aigoals.h"
242 #include "parselo.h"
243 #include "management.h"
244 #include "linklist.h"
245 #include "initialstatus.h"
246 #include "weaponeditordlg.h"
247 #include "ship.h"
248 #include "textviewdlg.h"
249 #include "player.h"                             // used for the max_keyed_target stuff
250 #include "ignoreordersdlg.h"
251 #include "missionparse.h"
252 #include "model.h"
253 #include "starfield.h"
254 #include "jumpnode.h"
255 #include "shipflagsdlg.h"
256 #include "missionmessage.h"
257 #include "shipspecialdamage.h"
258
259 #define ID_SHIP_MENU 9000
260
261 #define NO_PERSONA_INDEX        999
262
263 #ifdef _DEBUG
264 #define new DEBUG_NEW
265 #undef THIS_FILE
266 static char THIS_FILE[] = __FILE__;
267 #endif
268
269 void numeric_edit_control::setup(int id, CWnd *wnd)
270 {
271         control_id = id;
272         dlg = wnd;
273 }
274
275 void numeric_edit_control::init(int n)
276 {
277         value = n;
278         unique = 1;
279 }
280
281 void numeric_edit_control::set(int n)
282 {
283         if (n != value){
284                 unique = 0;
285         }
286 }
287
288 void numeric_edit_control::display()
289 {
290         CString str;
291
292         if (unique){
293                 str.Format("%d", value);
294         }
295
296         dlg->GetDlgItem(control_id)->SetWindowText(str);
297 }
298
299 void numeric_edit_control::save(int *n)
300 {
301         CString str;
302
303         if (control_id) {
304                 dlg->GetDlgItem(control_id)->GetWindowText(str);
305                 if (!str.IsEmpty()){
306                         MODIFY(*n, atoi(str));
307                 }
308         }
309 }
310
311 void numeric_edit_control::fix(int n)
312 {
313         if (unique) {
314                 CString str;
315                 CWnd *w;
316
317                 value = n;
318                 str.Format("%d", n);
319                 w = dlg->GetDlgItem(control_id);
320                 dlg->GetDlgItem(control_id)->SetWindowText(str);
321         }
322 }
323
324 /////////////////////////////////////////////////////////////////////////////
325 // CShipEditorDlg dialog
326
327 CShipEditorDlg::CShipEditorDlg(CWnd* pParent /*=NULL*/)
328         : CDialog(CShipEditorDlg::IDD, pParent)
329 {
330         //{{AFX_DATA_INIT(CShipEditorDlg)
331         m_ship_name = _T("");
332         m_cargo1 = _T("");
333         m_ship_class = -1;
334         m_team = -1;
335         m_arrival_location = -1;
336         m_departure_location = -1;
337         m_ai_class = -1;
338         m_hotkey = -1;
339         m_update_arrival = FALSE;
340         m_update_departure = FALSE;
341         m_arrival_target = -1;
342         m_departure_target = -1;
343         m_persona = -1; 
344         //}}AFX_DATA_INIT
345
346         m_pSEView = NULL;
347         initialized = editing = multi_edit = 0;
348         select_sexp_node = -1;
349         bypass_errors = 0;
350 }
351
352 //      Modeless constructor, MK
353 CShipEditorDlg::CShipEditorDlg(CView* pView)
354 {
355         m_pSEView = pView;
356         initialized = editing = 0;
357         select_sexp_node = -1;
358 }
359
360 void CShipEditorDlg::DoDataExchange(CDataExchange* pDX)
361 {
362         int n;
363         CString str;
364
365         CDialog::DoDataExchange(pDX);
366         //{{AFX_DATA_MAP(CShipEditorDlg)
367         DDX_Control(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp);
368         DDX_Control(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp);
369         DDX_Control(pDX, IDC_PLAYER_SHIP, m_player_ship);
370         DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin);
371         DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin);
372         DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree);
373         DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree);
374         DDX_Text(pDX, IDC_SHIP_NAME, m_ship_name);
375         DDX_CBString(pDX, IDC_SHIP_CARGO1, m_cargo1);
376         DDX_CBIndex(pDX, IDC_SHIP_CLASS, m_ship_class);
377         DDX_CBIndex(pDX, IDC_SHIP_TEAM, m_team);
378         DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location);
379         DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location);
380         DDX_CBIndex(pDX, IDC_AI_CLASS, m_ai_class);
381         DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey);
382         DDX_Check(pDX, IDC_UPDATE_ARRIVAL, m_update_arrival);
383         DDX_Check(pDX, IDC_UPDATE_DEPARTURE, m_update_departure);
384         DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target);
385         DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target);
386         DDX_CBIndex(pDX, IDC_SHIP_PERSONA, m_persona);  
387         //}}AFX_DATA_MAP
388         DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1);
389         DDV_MaxChars(pDX, m_cargo1, NAME_LENGTH - 1);
390
391         if (pDX->m_bSaveAndValidate) {  // get dialog control values
392                 GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str);
393                 n = atoi(str);
394                 if (n < 0){
395                         n = 0;
396                 }
397
398                 m_arrival_delay.init(n);
399
400                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->GetWindowText(str);
401                 m_arrival_dist.init(atoi(str));
402
403                 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
404                 n = atoi(str);
405                 if (n < 0)
406                         n = 0;
407                 m_departure_delay.init(n);
408
409                 GetDlgItem(IDC_SCORE)->GetWindowText(str);
410                 m_score.init(atoi(str));
411         }
412 }
413
414 BEGIN_MESSAGE_MAP(CShipEditorDlg, CDialog)
415         //{{AFX_MSG_MAP(CShipEditorDlg)
416         ON_WM_CLOSE()
417         ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree)
418         ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree)
419         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree)
420         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree)
421         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree)
422         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree)
423         ON_BN_CLICKED(IDC_GOALS, OnGoals)
424         ON_CBN_SELCHANGE(IDC_SHIP_CLASS, OnSelchangeShipClass)
425         ON_BN_CLICKED(IDC_INITIAL_STATUS, OnInitialStatus)
426         ON_BN_CLICKED(IDC_WEAPONS, OnWeapons)
427         ON_BN_CLICKED(IDC_SHIP_RESET, OnShipReset)
428         ON_BN_CLICKED(IDC_DELETE_SHIP, OnDeleteShip)
429         ON_BN_CLICKED(IDC_SHIP_TBL, OnShipTbl)
430         ON_BN_CLICKED(IDC_NEXT, OnNext)
431         ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree)
432         ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree)
433         ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues)
434         ON_BN_CLICKED(IDC_PREV, OnPrev)
435         ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation)
436         ON_BN_CLICKED(IDC_PLAYER_SHIP, OnPlayerShip)
437         ON_BN_CLICKED(IDC_NO_ARRIVAL_WARP, OnNoArrivalWarp)
438         ON_BN_CLICKED(IDC_NO_DEPARTURE_WARP, OnNoDepartureWarp)
439         ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation)
440         ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey)
441         ON_BN_CLICKED(IDC_FLAGS, OnFlags)
442         ON_BN_CLICKED(IDC_IGNORE_ORDERS, OnIgnoreOrders)
443         ON_WM_INITMENU()
444         ON_BN_CLICKED(IDC_SPECIAL_EXP, OnSpecialExp)
445         //}}AFX_MSG_MAP
446 END_MESSAGE_MAP()
447
448 /////////////////////////////////////////////////////////////////////////////
449 // CShipEditorDlg message handlers
450
451 BOOL CShipEditorDlg::Create()
452 {
453         int i, index;
454         BOOL r;
455         CComboBox *ptr;
456
457         r = CDialog::Create(IDD, Fred_main_wnd);
458
459         ptr = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
460         ptr->ResetContent();
461         for (i=0; i<MAX_ARRIVAL_NAMES; i++){
462                 ptr->AddString(Arrival_location_names[i]);
463         }
464
465         ptr = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
466         ptr->ResetContent();
467         for (i=0; i<MAX_DEPARTURE_NAMES; i++){
468                 ptr->AddString(Departure_location_names[i]);
469         }
470
471         ptr = (CComboBox *) GetDlgItem(IDC_SHIP_CLASS);
472         ptr->ResetContent();
473         for (i=0; i<Num_ship_types; i++){
474                 ptr->AddString(Ship_info[i].name);
475         }
476
477         ptr = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
478         ptr->ResetContent();
479         for (i=0; i<Num_ai_classes; i++){
480                 ptr->AddString(Ai_class_names[i]);
481         }
482
483         // alternate ship name combobox         
484         ptr = (CComboBox *)GetDlgItem(IDC_SHIP_ALT);
485         ptr->ResetContent();
486         ptr->AddString("<none>");
487         ptr->SetCurSel(0);
488
489         // deal with the persona dialog
490         ptr = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
491         ptr->ResetContent();
492         index = ptr->AddString("<None>");
493         if ( index >= 0 ){
494                 ptr->SetItemData(index, NO_PERSONA_INDEX);
495         }       
496
497         for ( i = 0; i < Num_personas; i++ ) {
498                 if ( Personas[i].flags & PERSONA_FLAG_WINGMAN ) {
499                         int index;
500
501                         // don't bother putting any vasudan personas on the list -- done automatically by code
502 //                      if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
503 //                              continue;
504 //                      }
505
506                         CString persona_name = Personas[i].name;
507                         if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
508                                 persona_name += " -Vas";
509                         }
510
511                         index = ptr->AddString(persona_name);
512                         if ( index >= 0 ){
513                                 ptr->SetItemData(index, i);
514                         }
515                 }
516         }
517
518         m_score.setup(IDC_SCORE, this);
519         m_arrival_dist.setup(IDC_ARRIVAL_DISTANCE, this);
520         m_arrival_delay.setup(IDC_ARRIVAL_DELAY, this);
521         m_departure_delay.setup(IDC_DEPARTURE_DELAY, this);
522
523         m_hotkey = 0;
524         m_arrival_tree.link_modified(&modified);  // provide way to indicate trees are modified in dialog
525         m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
526         m_departure_tree.link_modified(&modified);
527         m_departure_tree.setup();
528         m_arrival_delay_spin.SetRange(0, 999);
529         m_departure_delay_spin.SetRange(0, 999);
530         initialize_data(1);     
531
532         return r;
533 }
534
535 //      This gets called when you click on the "X" button.  Note that OnClose
536 //      does not destroy the window.  It only hides it.
537 void CShipEditorDlg::OnClose()
538 {
539         if (verify() && (!bypass_errors)) {
540                 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
541                 bypass_errors = 0;
542                 return;
543         }
544
545         if (update_data()) {
546                 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
547                 bypass_errors = 0;
548                 return;
549         }
550
551         SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
552         Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
553 }
554
555 BOOL CShipEditorDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
556 {
557         BOOL r;
558
559         r = CDialog::Create(IDD, pParentWnd);
560         return r;
561 }
562
563 int CShipEditorDlg::tristate_set(int val, int cur_state)
564 {
565         if (val) {
566                 if (!cur_state){
567                         return 2;
568                 }
569
570         } else {
571                 if (cur_state){
572                         return 2;
573                 }
574         }
575
576         return cur_state;
577 }
578
579 // called to initialize the dialog box to reflect what ships we currently have marked.  Any
580 // time what we have marked changes, this should get called again.
581 //
582 // Notes: player_count is the number of player starts marked, when we are in a non-multiplayer
583 // mission (NMM).  In a multiplayer mission (MM), player_count will always be zero.
584 // ship_count in NMM is the number of ships (i.e. not player starts) that are marked.  In MM,
585 // ship_count is the number of ships and player starts.  Total_count is the sum of ship_count
586 // and player_count in all cases.  The reason player_count isn't used in MM, and ship_count
587 // is used instead to track player starts is because in MM, player starts can be edited as
588 // freely as AI ships, and are very likely to be AI ships sometimes.  Thus, treating them like
589 // AI ships instead of player starts simplifies processing.
590 //
591 void CShipEditorDlg::initialize_data(int full_update)
592 {
593         int i, type, ship_count, player_count, total_count, wing = -1, pvalid_count;
594         int a_cue, d_cue, cue_init = 0, cargo = 0, base_ship, base_player, pship = -1;
595         int no_arrival_warp = 0, no_departure_warp = 0, escort_count, ship_orders, current_orders;
596         int pship_count;  // a total count of the player ships not marked
597         object *objp;
598         CWnd *w = NULL;
599         CString str;
600         CComboBox *box, *departure_box;
601         CSingleLock sync(&CS_update);
602
603         nprintf(("Fred routing", "Ship dialog load\n"));
604         if (!GetSafeHwnd() || bypass_all)
605                 return;
606
607         sync.Lock();  // don't initialize if we are still updating.  Wait until update is done.
608
609         box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
610         management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
611
612         departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
613         management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
614
615         if (The_mission.game_type & MISSION_TYPE_MULTI){
616                 mission_type = 0;  // multi player mission
617         } else {
618                 mission_type = 1;  // non-multiplayer mission (implies single player mission I guess)
619         }
620
621         // figure out what all we are editing.
622         ship_count = player_count = escort_count = pship_count = pvalid_count = 0;
623         base_ship = base_player = -1;
624         enable = p_enable = 1;
625         objp = GET_FIRST(&obj_used_list);
626         while (objp != END_OF_LIST(&obj_used_list)) {
627                 if ((objp->type == OBJ_SHIP) && (Ships[objp->instance].flags & SF_ESCORT)){
628                         escort_count++;  // get a total count of escort ships
629                 }
630
631                 if (objp->type == OBJ_START){
632                         pship_count++;  // count all player starts in mission
633                 }
634
635                 if (objp->flags & OF_MARKED) {
636                         type = objp->type;
637                         if ((type == OBJ_START) && !mission_type){  // in multiplayer missions, starts act like ships
638                                 type = OBJ_SHIP;
639                         }
640
641                         i = -1;
642                         if (type == OBJ_START) {
643                                 player_count++;
644                                 // if player_count is 1, base_player will be the one and only player
645                                 i = base_player = objp->instance;
646
647                         } else if (type == OBJ_SHIP) {
648                                 ship_count++;
649                                 // if ship_count is 1, base_ship will be the one and only ship
650                                 i = base_ship = objp->instance;
651                         }
652
653                         if (i >= 0){
654                                 if (Ship_info[Ships[i].ship_info_index].flags & SIF_PLAYER_SHIP){
655                                         pvalid_count++;
656                                 }
657                         }
658                 }
659
660                 objp = GET_NEXT(objp);
661         }
662
663         total_count = ship_count + player_count;  // get total number of objects being edited.
664         if (total_count > 1){
665                 multi_edit = 1;
666         } else {
667                 multi_edit = 0;
668         }
669
670         a_cue = d_cue = -1;
671         m_arrival_location = -1;
672         m_arrival_dist.blank();
673         m_arrival_target = -1;
674         m_arrival_delay.blank();
675         m_departure_location = -1;
676         m_departure_target = -1;
677         m_departure_delay.blank();
678
679         player_ship = single_ship = -1;
680         m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
681         select_sexp_node = -1;
682         ship_orders = 0;                                // assume they are all the same type
683         if (ship_count) {
684                 box = (CComboBox *) GetDlgItem(IDC_SHIP_CARGO1);
685                 box->ResetContent();
686                 for (i=0; i<Num_cargo; i++){
687                         box->AddString(Cargo_names[i]);
688                 }
689                 
690                 if (!multi_edit) {
691                         Assert((ship_count == 1) && (base_ship >= 0));
692                         m_ship_name = Ships[base_ship].ship_name;                       
693                 } else {
694                         m_ship_name = _T("");
695                 }
696
697                 m_update_arrival = m_update_departure = 1;
698                 base_player = 0;
699                 objp = GET_FIRST(&obj_used_list);
700                 while (objp != END_OF_LIST(&obj_used_list)) {
701                         if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) {
702                                 if (objp->flags & OF_MARKED) {
703                                         // do processing for both ships and players
704                                         i = get_ship_from_obj(objp);
705                                         if (base_player >= 0) {
706                                                 m_ship_class = Ships[i].ship_info_index;
707                                                 m_team = bitmask_2_bitnum(Ships[i].team);
708                                                 pship = (objp->type == OBJ_START) ? 1 : 0;
709                                                 base_player = -1;
710
711                                         } else {
712                                                 if (Ships[i].ship_info_index != m_ship_class)
713                                                         m_ship_class = -1;
714                                                 if (bitmask_2_bitnum(Ships[i].team) != m_team)
715                                                         m_team = -1;
716
717                                                 pship = tristate_set(Objects[Ships[i].objnum].type == OBJ_START, pship);
718                                         }
719
720                                         // 'and' in the ship type of this ship to our running bitfield
721                                         current_orders = ship_get_default_orders_accepted( &Ship_info[Ships[i].ship_info_index] );
722                                         if (!ship_orders){
723                                                 ship_orders = current_orders;
724                                         } else if (ship_orders != current_orders){
725                                                 ship_orders = -1;
726                                         }
727
728                                         if (Ships[i].flags & SF_ESCORT){
729                                                 escort_count--;  // remove marked escorts from count
730                                         }
731
732                                         if (Objects[Ships[i].objnum].type == OBJ_START){
733                                                 pship_count--;  // removed marked starts from count
734                                         }
735
736                                         // do processing only for ships (plus players if in a multiplayer mission
737                                         if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) {
738                                                 // process this if ship not in a wing
739                                                 if (Ships[i].wingnum < 0) {
740                                                         if (!cue_init) {
741                                                                 cue_init = 1;
742                                                                 a_cue = Ships[i].arrival_cue;
743                                                                 d_cue = Ships[i].departure_cue;
744                                                                 m_arrival_location = Ships[i].arrival_location;
745                                                                 m_arrival_dist.init(Ships[i].arrival_distance);
746                                                                 m_arrival_target = Ships[i].arrival_anchor;
747                                                                 m_arrival_delay.init(Ships[i].arrival_delay);
748                                                                 m_departure_location = Ships[i].departure_location;
749                                                                 m_departure_delay.init(Ships[i].departure_delay);
750                                                                 m_departure_target = Ships[i].departure_anchor;
751
752                                                         } else {
753                                                                 cue_init++;
754                                                                 if (Ships[i].arrival_location != m_arrival_location){
755                                                                         m_arrival_location = -1;
756                                                                 }
757
758                                                                 if (Ships[i].departure_location != m_departure_location){
759                                                                         m_departure_location = -1;
760                                                                 }
761
762                                                                 m_arrival_dist.set(Ships[i].arrival_distance);
763                                                                 m_arrival_delay.set(Ships[i].arrival_delay);
764                                                                 m_departure_delay.set(Ships[i].departure_delay);
765
766                                                                 if (Ships[i].arrival_anchor != m_arrival_target){
767                                                                         m_arrival_target = -1;
768                                                                 }
769
770                                                                 if (!cmp_sexp_chains(a_cue, Ships[i].arrival_cue)) {
771                                                                         a_cue = -1;
772                                                                         m_update_arrival = 0;
773                                                                 }
774
775                                                                 if (!cmp_sexp_chains(d_cue, Ships[i].departure_cue)) {
776                                                                         d_cue = -1;
777                                                                         m_update_departure = 0;
778                                                                 }
779
780                                                                 if ( Ships[i].departure_anchor != m_departure_target ){
781                                                                         m_departure_target = -1;
782                                                                 }
783                                                         }
784                                                 }
785
786                                                 // process the first ship in group, else process the rest
787                                                 if (base_ship >= 0) {
788                                                         m_ai_class = Ships[i].weapons.ai_class;
789                                                         cargo = Ships[i].cargo1;
790                                                         m_cargo1 = Cargo_names[cargo];
791                                                         m_hotkey = Ships[i].hotkey + 1;
792                                                         m_score.init(Ships[i].score);
793
794                                                         m_persona = Ships[i].persona_index + 1;
795
796                                                         // we use final_death_time member of ship structure for holding the amount of time before a mission
797                                                         // to destroy this ship
798                                                         wing = Ships[i].wingnum;
799                                                         if (wing < 0) {
800                                                                 GetDlgItem(IDC_WING) -> SetWindowText("None");
801
802                                                         } else {
803                                                                 GetDlgItem(IDC_WING) -> SetWindowText(Wings[wing].name);
804                                                                 if (!query_whole_wing_marked(wing))
805                                                                         m_update_arrival = m_update_departure = 0;
806                                                         }
807
808                                                         // set routine local varaiables for ship/object flags
809                                                         no_arrival_warp = (Ships[i].flags & SF_NO_ARRIVAL_WARP) ? 1 : 0;
810                                                         no_departure_warp = (Ships[i].flags & SF_NO_DEPARTURE_WARP) ? 1 : 0;
811
812                                                         base_ship = -1;
813                                                         if (!multi_edit)
814                                                                 single_ship = i;
815
816                                                 } else {
817                                                         if (Ships[i].weapons.ai_class != m_ai_class){
818                                                                 m_ai_class = -1;
819                                                         }
820
821                                                         if (Ships[i].cargo1 != cargo){
822                                                                 m_cargo1 = _T("");
823                                                         }
824
825                                                         m_score.set(Ships[i].score);
826
827                                                         if (Ships[i].hotkey != m_hotkey - 1){
828                                                                 m_hotkey = -1;
829                                                         }
830
831                                                         if ( Ships[i].persona_index != (m_persona-1) ){
832                                                                 m_persona = -1;
833                                                         }
834                                                         
835                                                         if (Ships[i].wingnum != wing){
836                                                                 GetDlgItem(IDC_WING) -> SetWindowText("");
837                                                         }
838
839                                                         no_arrival_warp = tristate_set(Ships[i].flags & SF_NO_ARRIVAL_WARP, no_arrival_warp);
840                                                         no_departure_warp = tristate_set(Ships[i].flags & SF_NO_DEPARTURE_WARP, no_departure_warp);
841                                                 }
842                                         }
843                                 }
844                         }
845
846                         objp = GET_NEXT(objp);
847                 }
848
849                 if (multi_edit) {
850                         m_arrival_tree.clear_tree("");
851                         m_departure_tree.clear_tree("");
852                 }
853
854                 if (cue_init) {
855                         m_arrival_tree.load_tree(a_cue);
856                         m_departure_tree.load_tree(d_cue, "false");
857
858                 } else {
859                         m_arrival_tree.clear_tree();
860                         m_arrival_tree.DeleteAllItems();
861                         m_departure_tree.clear_tree();
862                         m_departure_tree.DeleteAllItems();
863                 }
864
865                 m_player_ship.SetCheck(pship);
866                 m_no_arrival_warp.SetCheck(no_arrival_warp);
867                 m_no_departure_warp.SetCheck(no_departure_warp);
868
869                 if (!multi_edit) {
870                         i = m_arrival_tree.select_sexp_node;
871                         if (i != -1) {
872                                 w = GetDlgItem(IDC_ARRIVAL_TREE);
873                                 m_arrival_tree.hilite_item(i);
874
875                         } else {
876                                 i = m_departure_tree.select_sexp_node;
877                                 if (i != -1) {
878                                         w = GetDlgItem(IDC_DEPARTURE_TREE);
879                                         m_departure_tree.hilite_item(i);
880                                 }
881                         }
882                 }
883
884         } else {  // no ships selected, 0 or more player ships selected
885                 if (player_count > 1) {  // multiple player ships selected
886                         Assert(base_player >= 0);
887                         m_ship_name = _T("");
888                         m_player_ship.SetCheck(TRUE);
889                         objp = GET_FIRST(&obj_used_list);
890                         while (objp != END_OF_LIST(&obj_used_list)) {
891                                 if ((objp->type == OBJ_START) && (objp->flags & OF_MARKED)) {
892                                         i = objp->instance;
893                                         if (base_player >= 0) {
894                                                 m_ship_class = Ships[i].ship_info_index;
895                                                 m_team = bitmask_2_bitnum(Ships[i].team);
896                                                 base_player = -1;
897
898                                         } else {
899                                                 if (Ships[i].ship_info_index != m_ship_class)
900                                                         m_ship_class = -1;
901                                                 if (bitmask_2_bitnum(Ships[i].team) != m_team)
902                                                         m_team = -1;
903                                         }
904                                 }
905
906                                 objp = GET_NEXT(objp);
907                         }
908
909                 // only 1 player selected..
910                 } else if (query_valid_object() && (Objects[cur_object_index].type == OBJ_START)) {
911                         Assert((player_count == 1) && !multi_edit);
912                         player_ship = Objects[cur_object_index].instance;
913                         m_ship_name = Ships[player_ship].ship_name;
914                         m_ship_class = Ships[player_ship].ship_info_index;
915                         m_team = bitmask_2_bitnum(Ships[player_ship].team);
916                         m_player_ship.SetCheck(TRUE);
917
918                 } else {  // no ships or players selected..
919                         m_ship_name = _T("");
920                         m_ship_class = -1;
921                         m_team = -1;
922                         m_persona = -1;
923                         m_player_ship.SetCheck(FALSE);
924                 }
925
926                 m_ai_class = -1;
927                 m_cargo1 = _T("");
928                 m_hotkey = 0;
929                 m_score.blank();  // cause control to be blank
930                 m_arrival_location = -1;
931                 m_departure_location = -1;
932                 m_arrival_delay.blank();
933                 m_departure_delay.blank();
934                 m_arrival_dist.blank();
935                 m_arrival_target = -1;
936                 m_departure_target = -1;
937                 m_arrival_tree.clear_tree();
938                 m_arrival_tree.DeleteAllItems();
939                 m_departure_tree.clear_tree();
940                 m_departure_tree.DeleteAllItems();
941                 m_no_arrival_warp.SetCheck(0);
942                 m_no_departure_warp.SetCheck(0);
943                 enable = p_enable = 0;
944                 GetDlgItem(IDC_WING)->SetWindowText(_T("None"));
945         }
946
947         box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
948         // must put the appropriate ships into the list depending on arrival location
949         if ( m_arrival_location != ARRIVE_FROM_DOCK_BAY ){
950                 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
951         } else {
952                 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
953         }
954
955         // set the internal variable appropriatly
956         if (m_arrival_target >= SPECIAL_ARRIVAL_ANCHORS_OFFSET){
957                 m_arrival_target -= SPECIAL_ARRIVAL_ANCHORS_OFFSET;
958         } else if (m_arrival_target >= 0) {
959                 m_arrival_target = box->FindStringExact(-1, Ships[m_arrival_target].ship_name);
960         }
961
962         box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
963         // must put the appropriate ships into the list depending on departure location
964         if ( m_departure_location == DEPART_AT_DOCK_BAY ){
965                 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
966         } else {
967                 box->ResetContent();
968         }
969
970         if ( m_departure_target >= 0 ){
971                 m_departure_target = box->FindStringExact( -1, Ships[m_departure_target].ship_name );
972         }
973
974         initialized = 1;
975         if (player_count) {
976                 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
977                 if (!mission_type){  // multiplayer mission
978                         box->EnableWindow(TRUE);
979                 }
980
981                 else {
982                         box->EnableWindow(FALSE);
983                         m_team = -1;
984                 }
985
986                 box->ResetContent();
987                 for (i=0; i<2; i++)  // hard coded: only allow friendly and hostile
988                         box->AddString(Team_names[i]);
989         } else {
990                 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
991                 box->EnableWindow(enable);
992                 box->ResetContent();
993                 for (i=0; i<Num_team_names; i++){
994                         box->AddString(Team_names[i]);
995                 }
996         }       
997
998         m_score.display();
999         m_arrival_dist.display();
1000         m_arrival_delay.display();
1001         m_departure_delay.display();
1002
1003         if (full_update)
1004                 UpdateData(FALSE);
1005
1006         if (!cue_init) {
1007                 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(FALSE);
1008                 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(FALSE);
1009                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1010                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1011                 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(FALSE);
1012                 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(FALSE);
1013                 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(FALSE);
1014                 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1015                 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(FALSE);
1016                 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(FALSE);
1017                 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(FALSE);
1018                 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(FALSE);
1019                 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(FALSE);
1020
1021         } else {
1022                 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable);
1023                 if (m_arrival_location) {
1024                         GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable);
1025                         GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable);
1026                 } else {
1027                         GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1028                         GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1029                 }
1030
1031                 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1032                 if ( m_departure_location ) {
1033                         GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
1034                 } else {
1035                         GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1036                 }
1037
1038                 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(enable);
1039                 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(enable);
1040                 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
1041                 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1042                 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable);
1043                 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable);
1044                 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable);
1045                 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable);
1046                 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable);
1047         }
1048
1049         if (total_count) {
1050                 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(!multi_edit);
1051                 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(TRUE);
1052                 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
1053                 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(TRUE);
1054                 GetDlgItem(IDC_WEAPONS)->EnableWindow(m_ship_class >= 0);
1055                 GetDlgItem(IDC_FLAGS)->EnableWindow(TRUE);
1056
1057         } else {
1058                 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(FALSE);
1059                 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(FALSE);
1060                 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
1061                 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(FALSE);
1062                 GetDlgItem(IDC_WEAPONS)->EnableWindow(FALSE);
1063                 GetDlgItem(IDC_FLAGS)->EnableWindow(FALSE);
1064         }
1065
1066         GetDlgItem(IDC_AI_CLASS)->EnableWindow(enable);
1067         GetDlgItem(IDC_SHIP_CARGO1)->EnableWindow(enable);
1068         GetDlgItem(IDC_HOTKEY)->EnableWindow(enable);
1069         if ((m_ship_class >= 0) && !(Ship_info[m_ship_class].flags & SIF_CARGO) && !(Ship_info[m_ship_class].flags & SIF_NO_SHIP_TYPE))
1070                 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1071         else if (multi_edit)
1072                 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1073         else
1074                 GetDlgItem(IDC_GOALS)->EnableWindow(FALSE);
1075
1076         // !pship_count used because if allowed to clear, we would have no player starts
1077         if (mission_type || !pship_count || (pship_count + total_count > MAX_PLAYERS) || (pvalid_count < total_count))
1078                 m_player_ship.EnableWindow(FALSE);
1079         else
1080                 m_player_ship.EnableWindow(TRUE);
1081
1082         GetDlgItem(IDC_DELETE_SHIP)->EnableWindow(enable);
1083         GetDlgItem(IDC_SHIP_RESET)->EnableWindow(enable);
1084         GetDlgItem(IDC_SCORE)->EnableWindow(enable);
1085
1086 #ifndef NDEBUG
1087         GetDlgItem(IDC_SHIP_TBL)->EnableWindow(m_ship_class >= 0);
1088 #else
1089         GetDlgItem(IDC_SHIP_TBL)->EnableWindow(0);
1090         GetDlgItem(IDC_SHIP_TBL)->ShowWindow(SW_HIDE);
1091 #endif
1092
1093         if (cue_init > 1) {  // more than one ship (players don't have cues to edit)
1094                 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_SHOW);
1095                 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_SHOW);
1096
1097         } else {
1098                 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_HIDE);
1099                 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_HIDE);
1100         }
1101
1102         if (multi_edit || (total_count > 1)) {
1103                 // we will allow the ignore orders dialog to be multi edit if all selected
1104                 // ships are the same type.  the ship_type (local) variable holds the ship types
1105                 // for all ships.  Determine how may bits set and enable/diable window
1106                 // as appropriate
1107                 if ( /*(m_team == -1) ||*/ (ship_orders == -1) ){
1108                         GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(FALSE);
1109                 } else {
1110                         GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(TRUE);
1111                 }
1112         } else
1113                 // always enabled when one ship is selected
1114                 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(enable);
1115
1116         // always enabled if >= 1 ship selected
1117         GetDlgItem(IDC_SHIP_PERSONA)->EnableWindow(enable);     
1118
1119         if (multi_edit){
1120                 SetWindowText("Edit Marked Ships");
1121         } else if (player_count) {
1122                 SetWindowText("Edit Player Ship");
1123         } else {
1124                 SetWindowText("Edit Ship");
1125         }
1126
1127         // setup alternate name stuff   
1128         if(player_ship >= 0){                           
1129                 ship_alt_name_init(player_ship);
1130         } else {                                
1131                 ship_alt_name_init(single_ship);
1132         }
1133
1134         modified = 0;
1135         if (w){
1136                 w->SetFocus();
1137         }
1138 }
1139
1140 // update ship structure(s) with dialog data.  The data is first checked for errors.  If
1141 // no errors occur, returns 0.  If an error occurs, returns -1.  If the update is bypassed,
1142 // returns 1.  Bypass is necessary to avoid an infinite loop, and it doesn't actually
1143 // update the data.  Bypass only occurs if bypass mode is active and we still get an error.
1144 // Once the error no longer occurs, bypass mode is cleared and data is updated.
1145 int CShipEditorDlg::update_data(int redraw)
1146 {
1147         char *str, old_name[255];
1148         object *ptr;
1149         int i, z, wing;
1150         CSingleLock sync(&CS_cur_object_index), sync2(&CS_update);
1151
1152         nprintf(("Fred routing", "Ship dialog save\n"));
1153         if (!GetSafeHwnd() || !initialized || bypass_all)
1154                 return 0;
1155
1156         sync.Lock();  // don't allow cur_object_index to change while we are using it
1157         sync2.Lock();  // don't allow reinitialization until we are done updating
1158         UpdateData(TRUE);
1159         UpdateData(TRUE);
1160         Wing_editor_dialog.update_data_safe();
1161         if (multi_edit) {  // editing multiple ships (ships and/or players)
1162                 ptr = GET_FIRST(&obj_used_list);
1163                 while (ptr != END_OF_LIST(&obj_used_list)) {
1164                         if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags & OF_MARKED))
1165                                 update_ship(get_ship_from_obj(ptr));
1166
1167                         ptr = GET_NEXT(ptr);
1168                 }
1169
1170         } else if (player_ship >= 0) {  // editing a single player
1171                 update_ship(player_ship);
1172
1173         } else if (single_ship >= 0) {  // editing a single ship
1174                 ptr = GET_FIRST(&obj_used_list);
1175                 while (ptr != END_OF_LIST(&obj_used_list)) {
1176                         if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (cur_object_index != OBJ_INDEX(ptr))) {
1177                                 str = Ships[ptr->instance].ship_name;
1178                                 if (!stricmp(m_ship_name, str)) {
1179                                         if (bypass_errors)
1180                                                 return 1;
1181
1182                                         bypass_errors = 1;
1183                                         z = MessageBox("This ship name is already being used by another ship\n"
1184                                                 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1185
1186                                         if (z == IDCANCEL)
1187                                                 return -1;
1188
1189                                         m_ship_name = _T(Ships[single_ship].ship_name);
1190                                         UpdateData(FALSE);
1191                                 }
1192                         }
1193
1194                         ptr = GET_NEXT(ptr);
1195                 }
1196
1197                 for (i=0; i<MAX_WINGS; i++)
1198                         if (Wings[i].wave_count && !stricmp(Wings[i].name, m_ship_name)) {
1199                                 if (bypass_errors)
1200                                         return 1;
1201
1202                                 bypass_errors = 1;
1203                                 z = MessageBox("This ship name is already being used by a wing\n"
1204                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1205
1206                                 if (z == IDCANCEL)
1207                                         return -1;
1208
1209                                 m_ship_name = _T(Ships[single_ship].ship_name);
1210                                 UpdateData(FALSE);
1211                         }
1212
1213                 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
1214                         if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_ship_name)) {
1215                                 if (bypass_errors)
1216                                         return 0;
1217
1218                                 bypass_errors = 1;
1219                                 z = MessageBox("This ship name is already being used by a waypoint path\n"
1220                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1221
1222                                 if (z == IDCANCEL)
1223                                         return -1;
1224
1225                                 m_ship_name = _T(Ships[single_ship].ship_name);
1226                                 UpdateData(FALSE);
1227                         }
1228
1229                 for (i=0; i<Num_jump_nodes; i++)
1230                         if (!stricmp(Jump_nodes[i].name, m_ship_name)) {
1231                                 if (bypass_errors)
1232                                         return 1;
1233
1234                                 bypass_errors = 1;
1235                                 z = MessageBox("This ship name is already being used by a jump node\n"
1236                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1237
1238                                 if (z == IDCANCEL)
1239                                         return -1;
1240
1241                                 m_ship_name = _T(Ships[single_ship].ship_name);
1242                                 UpdateData(FALSE);
1243                         }
1244
1245                 wing = Ships[single_ship].wingnum;
1246                 if (wing >= 0) {
1247                         Assert((wing < MAX_WINGS) && Wings[wing].wave_count);
1248                         for (i=0; i<Wings[wing].wave_count; i++)
1249                                 if (wing_objects[wing][i] == Ships[single_ship].objnum)
1250                                         break;
1251
1252                         Assert(i < Wings[wing].wave_count);
1253                         sprintf(old_name, "%s %d", Wings[wing].name, i + 1);
1254                         if (stricmp(old_name, m_ship_name)) {
1255                                 if (bypass_errors)
1256                                         return 0;
1257
1258                                 if (MessageBox("This ship is part of a wing, and it's name cannot be changed",
1259                                         NULL, MB_OKCANCEL) == IDCANCEL)
1260                                                 return -1;
1261
1262                                 m_ship_name = _T(old_name);
1263                                 UpdateData(FALSE);
1264                         }
1265                 }
1266
1267                 z = update_ship(single_ship);
1268                 if (z)
1269                         return z;
1270
1271                 strcpy(old_name, Ships[single_ship].ship_name);
1272                 string_copy(Ships[single_ship].ship_name, m_ship_name, NAME_LENGTH, 1);
1273                 str = Ships[single_ship].ship_name;
1274                 if (stricmp(old_name, str)) {
1275                         update_sexp_references(old_name, str);
1276                         ai_update_goal_references(REF_TYPE_SHIP, old_name, str);
1277                         for (i=0; i<Num_reinforcements; i++)
1278                                 if (!stricmp(old_name, Reinforcements[i].name)) {
1279                                         Assert(strlen(str) < NAME_LENGTH);
1280                                         strcpy(Reinforcements[i].name, str);
1281                                 }
1282
1283                         Update_window = 1;
1284                 }
1285         }
1286
1287         if (Player_start_shipnum < 0 || Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) {  // need a new single player start.
1288                 ptr = GET_FIRST(&obj_used_list);
1289                 while (ptr != END_OF_LIST(&obj_used_list)) {
1290                         if (ptr->type == OBJ_START) {
1291                                 Player_start_shipnum = ptr->instance;
1292                                 break;
1293                         }
1294
1295                         ptr = GET_NEXT(ptr);
1296                 }
1297         }
1298
1299         if (modified)
1300                 set_modified();
1301
1302         Wing_editor_dialog.initialize_data_safe(1);
1303         bypass_errors = 0;
1304         modified = 0;
1305
1306         if (redraw)
1307                 update_map_window();
1308
1309         return 0;
1310 }
1311
1312 int CShipEditorDlg::update_ship(int ship)
1313 {
1314         int z, d;
1315         CString str;
1316         CComboBox *box;
1317         int persona;
1318
1319         // THIS DIALOG IS THE SOME OF THE WORST CODE I HAVE EVER SEEN IN MY ENTIRE LIFE. 
1320         // IT TOOK A RIDICULOUSLY LONG AMOUNT OF TIME TO ADD 2 FUNCTIONS. OMG
1321         ship_alt_name_close(ship);
1322
1323         if ((Ships[ship].ship_info_index != m_ship_class) && (m_ship_class != -1)) {
1324                 change_ship_type(ship, m_ship_class);
1325                 set_modified();
1326         }
1327
1328         if (m_team != -1)
1329                 MODIFY(Ships[ship].team, 1 << m_team);
1330
1331         if (Objects[Ships[ship].objnum].type != OBJ_SHIP){
1332                 if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)){
1333                         return 0;
1334                 }
1335         }
1336
1337         if (m_ai_class != -1){
1338                 MODIFY(Ships[ship].weapons.ai_class, m_ai_class);
1339         }
1340         if (strlen(m_cargo1)) {
1341                 z = string_lookup(m_cargo1, Cargo_names, Num_cargo);
1342                 if (z == -1) {
1343                         Assert(Num_cargo < MAX_CARGO);
1344                         z = Num_cargo++;
1345                         strcpy(Cargo_names[z], m_cargo1);
1346                 }
1347
1348                 MODIFY(Ships[ship].cargo1, (char)z);
1349         }
1350
1351         m_score.save(&Ships[ship].score);
1352         if (m_arrival_location != -1)
1353                 MODIFY(Ships[ship].arrival_location, m_arrival_location);
1354         if (m_departure_location != -1)
1355                 MODIFY(Ships[ship].departure_location, m_departure_location);
1356
1357         // do the persona update
1358         // m_persona holds the index into the list.  Get the item data associated with this index and then
1359         // assign to the ship taking care that we check for the NO_PERSONA_INDEX id
1360         box = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
1361         persona = box->GetItemData(m_persona);
1362         if ( persona == NO_PERSONA_INDEX )
1363                 persona = -1;
1364
1365         MODIFY(Ships[ship].persona_index, persona);
1366
1367         if (Ships[ship].wingnum < 0) {
1368                 if (!multi_edit || m_update_arrival) {  // should we update the arrival cue?
1369                         if (Ships[ship].arrival_cue >= 0)
1370                                 free_sexp2(Ships[ship].arrival_cue);
1371
1372                         Ships[ship].arrival_cue = m_arrival_tree.save_tree();
1373                 }
1374
1375                 if (!multi_edit || m_update_departure) {
1376                         if (Ships[ship].departure_cue >= 0)
1377                                 free_sexp2(Ships[ship].departure_cue);
1378
1379                         Ships[ship].departure_cue = m_departure_tree.save_tree();
1380                 }
1381
1382                 m_arrival_dist.save(&Ships[ship].arrival_distance);
1383                 m_arrival_delay.save(&Ships[ship].arrival_delay);
1384                 m_departure_delay.save(&Ships[ship].departure_delay);
1385                 if (m_arrival_target >= 0) {
1386                         z = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
1387                         MODIFY(Ships[ship].arrival_anchor, z);
1388
1389                         // if the arrival is not hyperspace or docking bay -- force arrival distance to be
1390                         // greater than 2*radius of target.
1391                         if (((m_arrival_location != ARRIVE_FROM_DOCK_BAY) && (m_arrival_location != ARRIVE_AT_LOCATION)) && (z >= 0) && (z < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
1392                         d = int(min(500, 2.0f * Objects[Ships[ship].objnum].radius));
1393                                 if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) {
1394                                         str.Format("Ship must arrive at least %d meters away from target.\n"
1395                                                 "Value has been reset to this.  Use with caution!\r\n"
1396                                                 "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[ship].objnum].radius) );
1397
1398                                         MessageBox(str);
1399                                         if (Ships[ship].arrival_distance < 0)
1400                                                 Ships[ship].arrival_distance = -d;
1401                                         else
1402                                                 Ships[ship].arrival_distance = d;
1403
1404                                         m_arrival_dist.fix(Ships[ship].arrival_distance);
1405                                 }
1406                         }
1407                 }
1408                 z = ((CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
1409                 MODIFY(Ships[ship].departure_anchor, z );
1410         }
1411
1412         if (m_hotkey != -1)
1413                 MODIFY(Ships[ship].hotkey, m_hotkey - 1);
1414
1415         switch( m_no_arrival_warp.GetCheck() ) {
1416                 case 0:
1417                         if (Ships[ship].flags & SF_NO_ARRIVAL_WARP)
1418                                 set_modified();
1419
1420                         Ships[ship].flags &= ~SF_NO_ARRIVAL_WARP;
1421                         break;
1422
1423                 case 1:
1424                         if (!(Ships[ship].flags & SF_NO_ARRIVAL_WARP))
1425                                 set_modified();
1426
1427                         Ships[ship].flags |= SF_NO_ARRIVAL_WARP;
1428                         break;
1429         }
1430
1431         switch( m_no_departure_warp.GetCheck() ) {
1432                 case 0:
1433                         if (Ships[ship].flags & SF_NO_DEPARTURE_WARP)
1434                                 set_modified();
1435
1436                         Ships[ship].flags &= ~SF_NO_DEPARTURE_WARP;
1437                         break;
1438
1439                 case 1:
1440                         if (!(Ships[ship].flags & SF_NO_DEPARTURE_WARP))
1441                                 set_modified();
1442
1443                         Ships[ship].flags |= SF_NO_DEPARTURE_WARP;
1444                         break;
1445         }
1446
1447         switch (m_player_ship.GetCheck()) {
1448                 case 1:
1449                         if (Objects[Ships[ship].objnum].type != OBJ_START) {
1450                                 Player_starts++;
1451                                 set_modified();
1452                         }
1453
1454                         Objects[Ships[ship].objnum].type = OBJ_START;
1455                         break;
1456
1457                 case 0:
1458                         if (Objects[Ships[ship].objnum].type == OBJ_START) {
1459                                 Player_starts--;
1460                                 set_modified();
1461                         }
1462
1463                         Objects[Ships[ship].objnum].type = OBJ_SHIP;
1464                         break;
1465         }       
1466
1467         Update_ship = 1;
1468         return 0;
1469 }
1470
1471 void CShipEditorDlg::OnOK()
1472 {
1473         HWND h;
1474         CWnd *w;
1475
1476         w = GetFocus();
1477         if (w) {
1478                 h = w->m_hWnd;
1479                 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
1480                 ::SetFocus(h);
1481         }
1482 }
1483
1484 void CShipEditorDlg::OnInitMenu(CMenu *pMenu)
1485 {
1486         CMenu *m;
1487
1488         m = pMenu->GetSubMenu(0);
1489         clear_menu(m);
1490         generate_ship_popup_menu(m, ID_SHIP_MENU, MF_ENABLED, SHIP_FILTER_PLAYERS);
1491         if (cur_ship != -1)
1492                 m->CheckMenuItem(ID_SHIP_MENU + cur_ship, MF_BYCOMMAND | MF_CHECKED);
1493
1494         CWnd::OnInitMenu(pMenu);
1495 }
1496
1497 BOOL CShipEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam) 
1498 {
1499         int id, ship;
1500
1501         id = LOWORD(wParam);
1502         if (id >= ID_SHIP_MENU && id < ID_SHIP_MENU + MAX_SHIPS) {
1503                 if (!update_data()) {
1504                         ship = id - ID_SHIP_MENU;
1505                         unmark_all();
1506                         set_cur_object_index(Ships[ship].objnum);
1507                         return 1;
1508                 }
1509         }
1510
1511         return CDialog::OnCommand(wParam, lParam);
1512 }
1513
1514 void CShipEditorDlg::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1515 {
1516         m_arrival_tree.right_clicked(); 
1517         *pResult = 0;
1518 }
1519
1520 void CShipEditorDlg::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1521 {
1522         m_departure_tree.right_clicked();
1523         *pResult = 0;
1524 }
1525
1526 void CShipEditorDlg::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1527 {
1528         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1529
1530         if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1)    {
1531                 *pResult = 0;
1532                 modified = editing = 1;
1533
1534         } else
1535                 *pResult = 1;
1536 }
1537
1538 void CShipEditorDlg::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1539 {
1540         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1541
1542         if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1)  {
1543                 *pResult = 0;
1544                 modified = editing = 1;
1545
1546         } else
1547                 *pResult = 1;
1548 }
1549
1550 void CShipEditorDlg::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1551 {
1552         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1553
1554         *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1555         editing = 0;
1556 }
1557
1558 void CShipEditorDlg::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1559 {
1560         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1561
1562         *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1563         editing = 0;
1564 }
1565
1566 int CShipEditorDlg::verify()
1567 {
1568         nprintf(("Fred routing", "Ship dialog verify\n"));
1569         if (!GetSafeHwnd() || !modified)
1570                 return 0;
1571
1572         if (bypass_errors)
1573                 return 1;
1574
1575         return 0;
1576 }
1577
1578 void CShipEditorDlg::OnGoals()
1579 {
1580         ShipGoalsDlg dlg_goals;
1581
1582         Assert(query_valid_object());
1583 //      if (multi_edit)
1584 //              dlg_goals.initialize_multi();
1585 //
1586 //      else {
1587 //              Assert(single_ship != -1);
1588 //              dlg_goals.self_ship = single_ship;
1589 //              dlg_goals.initialize(Ai_info[Ships[single_ship].ai_index].goals);
1590 //      }
1591
1592         if (!multi_edit) {
1593                 Assert(single_ship != -1);
1594                 dlg_goals.self_ship = single_ship;
1595         }
1596
1597         dlg_goals.DoModal();
1598         if (!multi_edit && !query_initial_orders_empty(Ai_info[Ships[single_ship].ai_index].goals))
1599                 if ((Ships[single_ship].wingnum >= 0) && (query_initial_orders_conflict(Ships[single_ship].wingnum)))
1600                         MessageBox("This ship's wing also has initial orders", "Possible conflict");
1601 }
1602
1603 void CShipEditorDlg::OnSelchangeShipClass() 
1604 {
1605         object *ptr;
1606
1607         UpdateData(TRUE);
1608         UpdateData(TRUE);
1609         ptr = GET_FIRST(&obj_used_list);
1610         while (ptr != END_OF_LIST(&obj_used_list)) {
1611                 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags & OF_MARKED))
1612                         if (Ships[ptr->instance].ship_info_index != m_ship_class) {
1613                                 change_ship_type(ptr->instance, m_ship_class);
1614                                 set_modified();
1615                         }
1616
1617                 ptr = GET_NEXT(ptr);
1618         }
1619
1620         update_map_window();
1621 }
1622
1623 void CShipEditorDlg::OnInitialStatus() 
1624 {
1625         initial_status dlg;
1626
1627         dlg.m_multi_edit = multi_edit;
1628         dlg.DoModal();
1629 }
1630
1631 void CShipEditorDlg::OnWeapons() 
1632 {
1633         int i, ship = -1;
1634         WeaponEditorDlg dlg;
1635         object *objp;
1636         CComboBox *box;
1637
1638         dlg.m_multi_edit = multi_edit;
1639         dlg.DoModal();
1640
1641         if (multi_edit) {
1642                 objp = GET_FIRST(&obj_used_list);
1643                 while (objp != END_OF_LIST(&obj_used_list)) {
1644                         if (objp->flags & OF_MARKED)
1645                                 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
1646                                         i = objp->instance;
1647                                         if (ship) {
1648                                                 if (Ships[i].weapons.ai_class != Ships[ship].weapons.ai_class)
1649                                                         m_ai_class = -1;
1650
1651                                         } else {
1652                                                 ship = i;
1653                                                 m_ai_class = Ships[i].weapons.ai_class;
1654                                         }
1655                                 }
1656
1657                         objp = GET_NEXT(objp);
1658                 }
1659
1660         } else {
1661                 ship = single_ship;
1662                 if (ship < 0)
1663                         ship = player_ship;
1664
1665                 Assert(ship >= 0);
1666                 m_ai_class = Ships[ship].weapons.ai_class;
1667         }
1668
1669         box = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
1670         box->SetCurSel(m_ai_class);
1671 }
1672
1673 void CShipEditorDlg::OnShipReset() 
1674 {
1675         int i, j, index, ship;
1676         object *objp;
1677         ship_info *sip;
1678         ship_subsys *ptr;
1679         ship_weapon *wp;
1680         model_subsystem *sp;
1681
1682         m_cargo1 = "Nothing";
1683         m_ai_class = AI_DEFAULT_CLASS;
1684         if (m_ship_class) {
1685                 if (Ship_info[m_ship_class].species == SPECIES_SHIVAN)
1686                         m_team = TEAM_HOSTILE;
1687                 else
1688                         m_team = TEAM_FRIENDLY;
1689         }
1690
1691         objp = GET_FIRST(&obj_used_list);
1692         while (objp != END_OF_LIST(&obj_used_list)) {
1693                 if (((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) && (objp->flags & OF_MARKED)) {
1694                         ship = objp->instance;
1695
1696                         // reset ship goals
1697                         for (i=0; i<MAX_AI_GOALS; i++){
1698                                 Ai_info[Ships[ship].ai_index].goals[i].ai_mode = AI_GOAL_NONE;
1699                         }
1700
1701                         objp->phys_info.speed = 0.0f;
1702                         objp->shields[0] = 100.0f;
1703                         objp->hull_strength = 100.0f;
1704
1705                         sip = &Ship_info[Ships[ship].ship_info_index];
1706                         for (i=0; i<sip->num_primary_banks; i++)
1707                                 Ships[ship].weapons.primary_bank_weapons[i] = sip->primary_bank_weapons[i];
1708
1709                         for (i=0; i<sip->num_secondary_banks; i++) {
1710                                 Ships[ship].weapons.secondary_bank_weapons[i] = sip->secondary_bank_weapons[i];
1711                                 Ships[ship].weapons.secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i];
1712                         }
1713
1714                         index = 0;
1715                         ptr = GET_FIRST(&Ships[ship].subsys_list);
1716                         while (ptr != END_OF_LIST(&Ships[ship].subsys_list)) {
1717                                 ptr->current_hits = 0.0f;
1718                                 if (ptr->system_info->type == SUBSYSTEM_TURRET) {
1719                                         wp = &ptr->weapons;
1720                                         sp = &Ship_info[Ships[ship].ship_info_index].subsystems[index];
1721
1722                                         j = 0;
1723                                         for (i=0; i<MAX_PRIMARY_BANKS; i++){
1724                                                 if (sp->primary_banks[i] != -1){
1725                                                         wp->primary_bank_weapons[j++] = sp->primary_banks[i];
1726                                                 }
1727                                         }
1728
1729                                         wp->num_primary_banks = j;
1730                                         j = 0;
1731                                         for (i=0; i<MAX_SECONDARY_BANKS; i++){
1732                                                 if (sp->secondary_banks[i] != -1) {
1733                                                         wp->secondary_bank_weapons[j] = sp->secondary_banks[i];
1734                                                         wp->secondary_bank_capacity[j++] = sp->secondary_bank_capacity[i];
1735                                                 }
1736                                         }
1737
1738                                         wp->num_secondary_banks = j;
1739                                         for (i=0; i<MAX_SECONDARY_BANKS; i++){
1740                                                 wp->secondary_bank_ammo[i] = 100;
1741                                         }
1742                                 }
1743
1744                                 index++;
1745                                 ptr = GET_NEXT(ptr);
1746                         }
1747                 }
1748
1749                 objp = GET_NEXT(objp);
1750         }
1751
1752         UpdateData(FALSE);
1753         if (multi_edit){
1754                 MessageBox("Ships reset to ship class defaults");
1755         } else {
1756                 MessageBox("Ship reset to ship class defaults");
1757         }
1758 }
1759
1760 void CShipEditorDlg::OnDeleteShip() 
1761 {
1762         delete_marked();
1763         unmark_all();
1764 }
1765
1766 void CShipEditorDlg::OnShipTbl()
1767 {
1768         text_view_dlg dlg;
1769
1770         dlg.set(m_ship_class);
1771         dlg.DoModal();
1772 }
1773
1774 int CShipEditorDlg::make_ship_list(int *arr)
1775 {
1776         int n = 0;
1777         object *ptr;
1778
1779         ptr = GET_FIRST(&obj_used_list);
1780         while (ptr != END_OF_LIST(&obj_used_list)) {
1781                 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)){
1782                         arr[n++] = OBJ_INDEX(ptr);
1783                 }
1784
1785                 ptr = GET_NEXT(ptr);
1786         }
1787
1788         return n;
1789 }
1790
1791 void CShipEditorDlg::OnPrev() 
1792 {
1793         int i, n, arr[MAX_SHIPS];
1794
1795         if (!update_data()) {
1796                 n = make_ship_list(arr);
1797                 if (!n){
1798                         return;
1799                 }
1800
1801                 if (cur_ship < 0){
1802                         i = n - 1;
1803                 }
1804
1805                 else {
1806                         for (i=0; i<n; i++){
1807                                 if (Ships[cur_ship].objnum == arr[i]){
1808                                         break;
1809                                 }
1810                         }
1811
1812                         Assert(i < n);
1813                         i--;
1814                         if (i < 0){
1815                                 i = n - 1;
1816                         }
1817                 }
1818
1819                 unmark_all();
1820                 set_cur_object_index(arr[i]);
1821                 Ship_editor_dialog.initialize_data(1);
1822                 Update_ship = 0;
1823         }
1824
1825         return;
1826 }
1827
1828 void CShipEditorDlg::OnNext() 
1829 {
1830         int i, n, arr[MAX_SHIPS];
1831
1832         if (!update_data()) {
1833                 n = make_ship_list(arr);
1834                 if (!n)
1835                         return;
1836
1837                 if (cur_ship < 0)
1838                         i = 0;
1839
1840                 else {
1841                         for (i=0; i<n; i++)
1842                                 if (Ships[cur_ship].objnum == arr[i])
1843                                         break;
1844
1845                         Assert(i < n);
1846                         i++;
1847                         if (i == n)
1848                                 i = 0;
1849                 }
1850
1851                 unmark_all();
1852                 set_cur_object_index(arr[i]);
1853                 Ship_editor_dialog.initialize_data(1);
1854                 Update_ship = 0;
1855         }
1856
1857         return;
1858 }
1859
1860 void CShipEditorDlg::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1861 {
1862         HTREEITEM h;
1863
1864         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1865         h = pNMTreeView->itemNew.hItem;
1866         if (h){
1867                 m_arrival_tree.update_help(h);
1868         }
1869
1870         *pResult = 0;
1871 }
1872
1873 void CShipEditorDlg::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1874 {
1875         HTREEITEM h;
1876
1877         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1878         h = pNMTreeView->itemNew.hItem;
1879         if (h){
1880                 m_departure_tree.update_help(h);
1881         }
1882
1883         *pResult = 0;
1884 }
1885
1886 void CShipEditorDlg::calc_cue_height()
1887 {
1888         CRect cue;
1889
1890         GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1891         cue_height = cue.bottom - cue.top + 10;
1892         if (Show_sexp_help){
1893                 cue_height += SEXP_HELP_BOX_SIZE;
1894         }
1895
1896         if (Hide_ship_cues) {
1897                 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1898                 OnHideCues();
1899         }
1900 }
1901
1902 void CShipEditorDlg::show_hide_sexp_help()
1903 {
1904         CRect rect;
1905
1906         if (Show_sexp_help){
1907                 cue_height += SEXP_HELP_BOX_SIZE;
1908         } else {
1909                 cue_height -= SEXP_HELP_BOX_SIZE;
1910         }
1911
1912         if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()){
1913                 return;
1914         }
1915
1916         GetWindowRect(rect);
1917
1918         if (Show_sexp_help){
1919                 rect.bottom += SEXP_HELP_BOX_SIZE;
1920         } else {
1921                 rect.bottom -= SEXP_HELP_BOX_SIZE;
1922         }
1923
1924         MoveWindow(rect);
1925 }
1926
1927 void CShipEditorDlg::OnHideCues() 
1928 {
1929         CRect rect;
1930
1931         GetWindowRect(rect);
1932         if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1933                 rect.bottom -= cue_height;
1934                 Hide_ship_cues = 1;
1935
1936         } else {
1937                 rect.bottom += cue_height;
1938                 Hide_ship_cues = 0;
1939         }
1940
1941         MoveWindow(rect);
1942 }
1943
1944 void CShipEditorDlg::OnSelchangeArrivalLocation() 
1945 {
1946         CComboBox *box;
1947
1948         UpdateData();
1949         box = (CComboBox *)GetDlgItem( IDC_ARRIVAL_TARGET );
1950         if (m_arrival_location) {
1951                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE);
1952                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE);
1953                 if (m_arrival_target < 0) {
1954                         m_arrival_target = 0;
1955                 }
1956
1957                 // determine which items we should put into the arrival target combo box
1958                 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
1959                         management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1960                 } else {
1961                         management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1962                 }
1963
1964         } else {
1965                 m_arrival_target = -1;
1966                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1967                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1968         }
1969         UpdateData(FALSE);
1970 }
1971
1972 void CShipEditorDlg::OnSelchangeDepartureLocation() 
1973 {
1974         CComboBox *box;
1975
1976         UpdateData();
1977         box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1978         if ( m_departure_location ) {
1979                 box->EnableWindow(TRUE);
1980                 if ( m_departure_target < 0 ) {
1981                         m_departure_target = 0;
1982                 }
1983
1984                 // we need to build up the list box content based on the departure type.  When
1985                 // from a docking bay, only show ships in the list which have them.  Show all ships otherwise
1986                 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
1987                         management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1988                 } else {
1989                         // I think that this section is currently illegal
1990                         Int3();
1991                 }
1992
1993         } else {
1994                 m_departure_target = -1;
1995                 box->EnableWindow(FALSE);
1996         }
1997         UpdateData(FALSE);
1998 }
1999
2000
2001 void CShipEditorDlg::OnPlayerShip() 
2002 {
2003         if (m_player_ship.GetCheck() == 1)
2004                 m_player_ship.SetCheck(0);
2005         else
2006                 m_player_ship.SetCheck(1);
2007
2008         update_map_window();
2009 }
2010
2011 void CShipEditorDlg::OnNoArrivalWarp() 
2012 {
2013         if (m_no_arrival_warp.GetCheck() == 1)
2014                 m_no_arrival_warp.SetCheck(0);
2015         else
2016                 m_no_arrival_warp.SetCheck(1);
2017 }
2018
2019 void CShipEditorDlg::OnNoDepartureWarp() 
2020 {
2021         if (m_no_departure_warp.GetCheck() == 1)
2022                 m_no_departure_warp.SetCheck(0);
2023         else
2024                 m_no_departure_warp.SetCheck(1);
2025 }
2026
2027
2028 // function to possibly warn user when he selects a hotkey which might be used for
2029 // a player wing.
2030 void CShipEditorDlg::OnSelchangeHotkey() 
2031 {
2032         int set_num;
2033         char buf[256];
2034
2035         UpdateData(TRUE);
2036         set_num = m_hotkey-1;                   // use -1 since values associated with hotkey sets are 1 index based
2037
2038         // the first three sets are generally reserved for player starting wings.
2039         if ( set_num < MAX_STARTING_WINGS ) {
2040                 sprintf( buf, "This hotkey set should probably be reserved\nfor wing %s", Starting_wing_names[set_num] );
2041                 MessageBox(buf, NULL, MB_OK);
2042         }
2043 }
2044
2045 void CShipEditorDlg::OnFlags() 
2046 {
2047         ship_flags_dlg dlg;
2048
2049         dlg.setup(p_enable);
2050         dlg.DoModal();
2051 }
2052
2053 void CShipEditorDlg::OnIgnoreOrders() 
2054 {
2055         // TODO: Add your control notification handler code here
2056         ignore_orders_dlg player_order_dlg;
2057
2058         Assert(query_valid_object());
2059
2060         if (!multi_edit) {
2061                 if ( single_ship != -1 ){
2062                         player_order_dlg.m_ship = single_ship;
2063                 } else {
2064                         player_order_dlg.m_ship = player_ship;
2065                 }
2066         } else {
2067                 player_order_dlg.m_ship = -1;
2068         }
2069
2070         player_order_dlg.DoModal();
2071 }
2072
2073 void CShipEditorDlg::OnSpecialExp() 
2074 {
2075         // TODO: Add your control notification handler code here
2076         ShipSpecialDamage dlg;
2077         dlg.DoModal();
2078 }
2079
2080 // alternate ship name stuff
2081 void CShipEditorDlg::ship_alt_name_init(int base_ship)
2082 {
2083         int idx;
2084         CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2085         if(ptr == NULL){
2086                 Int3();
2087                 return;
2088         }
2089
2090         // multi-edit. bah      
2091         if(multi_edit){         
2092                 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
2093                 return;
2094         } 
2095         GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);   
2096
2097         // reset the combobox and add all relevant strings
2098         ptr->ResetContent();
2099         ptr->AddString("<none>");
2100         for(idx=0; idx<Mission_alt_type_count; idx++){
2101                 ptr->AddString(Mission_alt_types[idx]);
2102         }
2103
2104         // "none"
2105         if(base_ship < 0){
2106                 ptr->SetCurSel(0);
2107         }
2108
2109         // otherwise look his stuff up
2110         if(strlen(Fred_alt_names[base_ship])){
2111                 ptr->SelectString(0, Fred_alt_names[base_ship]);
2112         } else {
2113                 ptr->SetCurSel(0);
2114         }
2115 }
2116
2117 void CShipEditorDlg::ship_alt_name_close(int base_ship)
2118 {
2119         CString cstr;
2120         char str[NAME_LENGTH+2] = "";
2121         char *p;        
2122         CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2123
2124         if(multi_edit){
2125                 return;
2126         }
2127         
2128         if(ptr == NULL){
2129                 Int3();
2130                 return;
2131         }
2132
2133         // see if we have something besides "none" selected
2134         ptr->GetWindowText(cstr);
2135         if(cstr == CString("<none>")){
2136                 // zero the entry
2137                 strcpy(Fred_alt_names[base_ship], "");
2138
2139                 return;
2140         }       
2141         p = cstr.GetBuffer(0);
2142         if(p == NULL){
2143                 return;
2144         }
2145         strcpy(str, p);
2146
2147         // otherwise see if it already exists
2148         if(mission_parse_lookup_alt(str) >= 0){
2149                 strcpy(Fred_alt_names[base_ship], str);
2150
2151                 return;
2152         }
2153
2154         // otherwise try and add it
2155         if(mission_parse_add_alt(str) >= 0){
2156                 strcpy(Fred_alt_names[base_ship], str);
2157
2158                 return;
2159         }
2160
2161         // bad - couldn't add
2162         strcpy(Fred_alt_names[base_ship], "");
2163         MessageBox("Couldn't add new alternate type name. Already using too many!");
2164 }