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