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