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