2 * $Logfile: /Freespace2/code/fred2/ShipEditorDlg.cpp $
7 * Single ship editing dialog
10 * Revision 1.1 2002/05/03 03:28:08 root
14 * 8 8/18/99 1:32p Andsager
15 * Mark Vasudan wingmen as such.
17 * 7 8/18/99 1:12p Andsager
18 * Allow ships to be assigned Vasudan persona (wingman 6)
20 * 6 8/16/99 10:52p Andsager
21 * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
23 * 5 8/11/99 9:27a Andsager
24 * Fix compile warning.
26 * 4 5/20/99 6:59p Dave
27 * Added alternate type names for ships. Changed swarm missile table
30 * 3 2/11/99 2:15p Andsager
31 * Add ship explosion modification to FRED
33 * 2 10/07/98 6:28p Dave
34 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
35 * Fred. Globalized mission and campaign file extensions. Removed Silent
36 * Threat specific code.
38 * 1 10/07/98 3:02p Dave
40 * 1 10/07/98 3:00p Dave
42 * 157 6/16/98 10:17a Hoffoss
43 * Fixed define that was backwards and no one caught before release (ya,
46 * 156 5/23/98 3:33p Hoffoss
47 * Removed unused code in reinforcements editor and make ships.tbl button
48 * in ship editor disappear in release build.
50 * 155 5/21/98 12:58a Hoffoss
51 * Fixed warnings optimized build turned up.
53 * 154 4/28/98 2:13p Hoffoss
54 * Added code to help keep invalid player ship types from existing in
57 * 153 4/24/98 2:57p Jim
60 * 152 4/22/98 11:55a Hoffoss
61 * Fixed bug with ship editor's hide cue button when sexp help is on at
64 * 151 4/16/98 5:59p Duncan
65 * Fixed bad assumption, apparently.
67 * 150 4/07/98 9:42a Allender
68 * put in persona combo box into ship editor. Removed code to assign
69 * personas based on message
71 * 149 3/30/98 1:15p Hoffoss
72 * Fixed bug with arrival/departure cue window size calculation. Wasn't
73 * working anymore after my changes to dialog initing at startup.
75 * 148 3/27/98 12:02p Sandeep
77 * 147 3/25/98 4:14p Hoffoss
78 * Split ship editor up into ship editor and a misc dialog, which tracks
81 * 146 3/21/98 7:36p Lawrance
82 * Move jump nodes to own lib.
84 * 145 3/16/98 8:27p Allender
85 * Fred support for two new AI flags -- kamikaze and no dynamic goals.
87 * 144 3/10/98 6:11p Hoffoss
88 * Added jump node renaming abilities to Fred.
90 * 143 3/09/98 4:30p Allender
91 * multiplayer secondary weapon changes. red-alert and cargo-known-delay
92 * sexpressions. Add time cargo revealed to ship structure
94 * 142 2/22/98 1:21a Hoffoss
95 * Disabled weapon editor if mutliple ship types marked.
97 * 141 2/17/98 12:07p Hoffoss
98 * Changed over to using SF_CARGO_REVEALED in fred.
100 * 140 2/17/98 11:42a Hoffoss
101 * Added support for hidden from sensors condition.
103 * 139 2/13/98 2:42p Duncan
104 * Fixed bug, moved line down where it needs to be because
105 * pre-initializations need to be done first.
107 * 138 2/10/98 1:42p Allender
108 * allow > MAX_ESCORT_SHIPS to be marked as escort ships
110 * 137 2/06/98 2:54p Hoffoss
111 * Fixed some bugs in dialog init, and cleared up some of the confusion
112 * about how it works by renaming some variables and adding comments.
114 * 136 2/06/98 10:48a Hoffoss
115 * Fixed bug with not being able to make ships players in multi mode
118 * 135 2/04/98 4:32p Allender
119 * support for multiple briefings and debriefings. Changes to mission
120 * type (now a bitfield). Bitfield defs for multiplayer modes
122 * 134 1/29/98 5:14p Hoffoss
123 * Added support for a SF_INVULNERABLE ship flag in Fred.
125 * 133 1/12/98 10:41a Allender
126 * fixed minor bug with ship editor and ignore orders dialog
128 * 132 12/05/97 4:07p Hoffoss
129 * Changed code to allow WHO_FROM type ship sources to only show flyable
132 * 131 11/24/97 2:31p Allender
133 * allow ignore orders dialog to be active for players
135 * 130 11/24/97 9:07a Allender
136 * ignore orders dialog should function as multi-edit now
138 * 129 11/22/97 4:17p Allender
139 * first pass of making ignore orders dialog multi edit
141 * 128 11/13/97 4:14p Allender
142 * automatic assignment of hotkeys for starting wings. Appripriate
143 * warnings when they are incorrectly used. hotkeys correctly assigned to
144 * ships/wing arriving after mission start
146 * 127 11/11/97 3:32p Johnson
147 * allender: Combo boxes need to have lists initialized before setting
148 * internal class variable for arrival/depature targets
150 * 126 11/11/97 2:13p Allender
151 * docking bay support for Fred and Freespace. Added hook to ai code for
152 * arrival/departure from dock bays. Fred support now sufficient.
154 * 125 11/10/97 10:13p Allender
155 * added departure anchor to Fred and Freespace in preparation for using
156 * docking bays. Functional in Fred, not in FreeSpace.
158 * 124 10/21/97 4:49p Allender
159 * added flags to Fred and FreeSpace to forgo warp effect (toggle in ship
162 * 123 10/14/97 5:33p Hoffoss
163 * Added Fred support (and fsm support) for the no_arrival_music flags in
166 * 122 9/18/97 10:49a Allender
167 * increment/decrement Player_start variable when making a ship a player
170 * 121 9/17/97 5:43p Hoffoss
171 * Added Fred support for new player start information.
173 * 120 9/16/97 9:41p Hoffoss
174 * Changed Fred code around to stop using Parse_player structure for
175 * player information, and use actual ships instead.
177 * 119 9/15/97 2:35p Hoffoss
178 * Fixed bug in Fred where a player ship and normal ship both marked
179 * clobbered each other's ship type in ship editor dialog.
181 * 118 9/09/97 10:29a Hoffoss
182 * Added support for neutral team, and fixed changes made to how team is
183 * used in ship structure.
185 * 117 9/09/97 9:27a Hoffoss
186 * Removed #Jason Hoffoss# comments from code. Code is already set up to
187 * handle the situation properly.
189 * 116 9/06/97 2:13p Mike
190 * Replace support for TEAM_NEUTRAL
192 * 115 9/04/97 5:35p Hoffoss
193 * Fixed arrival distance stuff.
195 * 114 9/04/97 5:04p Johnson
196 * Fixed bug with arrival target distance checking.
198 * 113 9/04/97 4:31p Hoffoss
199 * Fixed bug: Changed ship editor to not touch wing info (arrival or
200 * departure cues) to avoid conflicts with wing editor's changes.
202 * 112 8/30/97 9:52p Hoffoss
203 * Implemented arrival location, distance, and anchor in Fred.
205 * 111 8/28/97 8:56a Hoffoss
206 * Added more checking to sexp error checker, fixed some bugs.
208 * 110 8/25/97 5:56p Hoffoss
209 * Added multiple asteroid field support, loading and saving of asteroid
210 * fields, and ship score field to Fred.
212 * 109 8/22/97 4:16p Hoffoss
213 * added support for arrival and departure info in ship editor using
214 * wing's info if editing marked ships in a wing instead of using ship's.
216 * 108 8/21/97 11:37p Hoffoss
217 * Fixed bug: when renaming a ship that is a reinforcement, an extra
218 * instance of it is added to the reinforcement list.
220 * 107 8/20/97 6:53p Hoffoss
221 * Implemented escort flag support in Fred.
223 * 106 8/19/97 2:53p Hoffoss
224 * Fixed bug where multiple ships editing doesn't change players.
226 * 105 8/19/97 1:44p Hoffoss
227 * Fixed bug with updating too quickly (i.e. via prev and next buttons).
235 #include "fredview.h"
243 #include "management.h"
244 #include "linklist.h"
245 #include "initialstatus.h"
246 #include "weaponeditordlg.h"
248 #include "textviewdlg.h"
249 #include "player.h" // used for the max_keyed_target stuff
250 #include "ignoreordersdlg.h"
251 #include "missionparse.h"
253 #include "starfield.h"
254 #include "jumpnode.h"
255 #include "shipflagsdlg.h"
256 #include "missionmessage.h"
257 #include "shipspecialdamage.h"
259 #define ID_SHIP_MENU 9000
261 #define NO_PERSONA_INDEX 999
264 #define new DEBUG_NEW
266 static char THIS_FILE[] = __FILE__;
269 void numeric_edit_control::setup(int id, CWnd *wnd)
275 void numeric_edit_control::init(int n)
281 void numeric_edit_control::set(int n)
288 void numeric_edit_control::display()
293 str.Format("%d", value);
296 dlg->GetDlgItem(control_id)->SetWindowText(str);
299 void numeric_edit_control::save(int *n)
304 dlg->GetDlgItem(control_id)->GetWindowText(str);
306 MODIFY(*n, atoi(str));
311 void numeric_edit_control::fix(int n)
319 w = dlg->GetDlgItem(control_id);
320 dlg->GetDlgItem(control_id)->SetWindowText(str);
324 /////////////////////////////////////////////////////////////////////////////
325 // CShipEditorDlg dialog
327 CShipEditorDlg::CShipEditorDlg(CWnd* pParent /*=NULL*/)
328 : CDialog(CShipEditorDlg::IDD, pParent)
330 //{{AFX_DATA_INIT(CShipEditorDlg)
331 m_ship_name = _T("");
335 m_arrival_location = -1;
336 m_departure_location = -1;
339 m_update_arrival = FALSE;
340 m_update_departure = FALSE;
341 m_arrival_target = -1;
342 m_departure_target = -1;
347 initialized = editing = multi_edit = 0;
348 select_sexp_node = -1;
352 // Modeless constructor, MK
353 CShipEditorDlg::CShipEditorDlg(CView* pView)
356 initialized = editing = 0;
357 select_sexp_node = -1;
360 void CShipEditorDlg::DoDataExchange(CDataExchange* pDX)
365 CDialog::DoDataExchange(pDX);
366 //{{AFX_DATA_MAP(CShipEditorDlg)
367 DDX_Control(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp);
368 DDX_Control(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp);
369 DDX_Control(pDX, IDC_PLAYER_SHIP, m_player_ship);
370 DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin);
371 DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin);
372 DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree);
373 DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree);
374 DDX_Text(pDX, IDC_SHIP_NAME, m_ship_name);
375 DDX_CBString(pDX, IDC_SHIP_CARGO1, m_cargo1);
376 DDX_CBIndex(pDX, IDC_SHIP_CLASS, m_ship_class);
377 DDX_CBIndex(pDX, IDC_SHIP_TEAM, m_team);
378 DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location);
379 DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location);
380 DDX_CBIndex(pDX, IDC_AI_CLASS, m_ai_class);
381 DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey);
382 DDX_Check(pDX, IDC_UPDATE_ARRIVAL, m_update_arrival);
383 DDX_Check(pDX, IDC_UPDATE_DEPARTURE, m_update_departure);
384 DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target);
385 DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target);
386 DDX_CBIndex(pDX, IDC_SHIP_PERSONA, m_persona);
388 DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1);
389 DDV_MaxChars(pDX, m_cargo1, NAME_LENGTH - 1);
391 if (pDX->m_bSaveAndValidate) { // get dialog control values
392 GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str);
398 m_arrival_delay.init(n);
400 GetDlgItem(IDC_ARRIVAL_DISTANCE)->GetWindowText(str);
401 m_arrival_dist.init(atoi(str));
403 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
407 m_departure_delay.init(n);
409 GetDlgItem(IDC_SCORE)->GetWindowText(str);
410 m_score.init(atoi(str));
414 BEGIN_MESSAGE_MAP(CShipEditorDlg, CDialog)
415 //{{AFX_MSG_MAP(CShipEditorDlg)
417 ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree)
418 ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree)
419 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree)
420 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree)
421 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree)
422 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree)
423 ON_BN_CLICKED(IDC_GOALS, OnGoals)
424 ON_CBN_SELCHANGE(IDC_SHIP_CLASS, OnSelchangeShipClass)
425 ON_BN_CLICKED(IDC_INITIAL_STATUS, OnInitialStatus)
426 ON_BN_CLICKED(IDC_WEAPONS, OnWeapons)
427 ON_BN_CLICKED(IDC_SHIP_RESET, OnShipReset)
428 ON_BN_CLICKED(IDC_DELETE_SHIP, OnDeleteShip)
429 ON_BN_CLICKED(IDC_SHIP_TBL, OnShipTbl)
430 ON_BN_CLICKED(IDC_NEXT, OnNext)
431 ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree)
432 ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree)
433 ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues)
434 ON_BN_CLICKED(IDC_PREV, OnPrev)
435 ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation)
436 ON_BN_CLICKED(IDC_PLAYER_SHIP, OnPlayerShip)
437 ON_BN_CLICKED(IDC_NO_ARRIVAL_WARP, OnNoArrivalWarp)
438 ON_BN_CLICKED(IDC_NO_DEPARTURE_WARP, OnNoDepartureWarp)
439 ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation)
440 ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey)
441 ON_BN_CLICKED(IDC_FLAGS, OnFlags)
442 ON_BN_CLICKED(IDC_IGNORE_ORDERS, OnIgnoreOrders)
444 ON_BN_CLICKED(IDC_SPECIAL_EXP, OnSpecialExp)
448 /////////////////////////////////////////////////////////////////////////////
449 // CShipEditorDlg message handlers
451 BOOL CShipEditorDlg::Create()
457 r = CDialog::Create(IDD, Fred_main_wnd);
459 ptr = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
461 for (i=0; i<MAX_ARRIVAL_NAMES; i++){
462 ptr->AddString(Arrival_location_names[i]);
465 ptr = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
467 for (i=0; i<MAX_DEPARTURE_NAMES; i++){
468 ptr->AddString(Departure_location_names[i]);
471 ptr = (CComboBox *) GetDlgItem(IDC_SHIP_CLASS);
473 for (i=0; i<Num_ship_types; i++){
474 ptr->AddString(Ship_info[i].name);
477 ptr = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
479 for (i=0; i<Num_ai_classes; i++){
480 ptr->AddString(Ai_class_names[i]);
483 // alternate ship name combobox
484 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_ALT);
486 ptr->AddString("<none>");
489 // deal with the persona dialog
490 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
492 index = ptr->AddString("<None>");
494 ptr->SetItemData(index, NO_PERSONA_INDEX);
497 for ( i = 0; i < Num_personas; i++ ) {
498 if ( Personas[i].flags & PERSONA_FLAG_WINGMAN ) {
501 // don't bother putting any vasudan personas on the list -- done automatically by code
502 // if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
506 CString persona_name = Personas[i].name;
507 if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
508 persona_name += " -Vas";
511 index = ptr->AddString(persona_name);
513 ptr->SetItemData(index, i);
518 m_score.setup(IDC_SCORE, this);
519 m_arrival_dist.setup(IDC_ARRIVAL_DISTANCE, this);
520 m_arrival_delay.setup(IDC_ARRIVAL_DELAY, this);
521 m_departure_delay.setup(IDC_DEPARTURE_DELAY, this);
524 m_arrival_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog
525 m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
526 m_departure_tree.link_modified(&modified);
527 m_departure_tree.setup();
528 m_arrival_delay_spin.SetRange(0, 999);
529 m_departure_delay_spin.SetRange(0, 999);
535 // This gets called when you click on the "X" button. Note that OnClose
536 // does not destroy the window. It only hides it.
537 void CShipEditorDlg::OnClose()
539 if (verify() && (!bypass_errors)) {
540 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
546 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
551 SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
552 Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
555 BOOL CShipEditorDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
559 r = CDialog::Create(IDD, pParentWnd);
563 int CShipEditorDlg::tristate_set(int val, int cur_state)
579 // called to initialize the dialog box to reflect what ships we currently have marked. Any
580 // time what we have marked changes, this should get called again.
582 // Notes: player_count is the number of player starts marked, when we are in a non-multiplayer
583 // mission (NMM). In a multiplayer mission (MM), player_count will always be zero.
584 // ship_count in NMM is the number of ships (i.e. not player starts) that are marked. In MM,
585 // ship_count is the number of ships and player starts. Total_count is the sum of ship_count
586 // and player_count in all cases. The reason player_count isn't used in MM, and ship_count
587 // is used instead to track player starts is because in MM, player starts can be edited as
588 // freely as AI ships, and are very likely to be AI ships sometimes. Thus, treating them like
589 // AI ships instead of player starts simplifies processing.
591 void CShipEditorDlg::initialize_data(int full_update)
593 int i, type, ship_count, player_count, total_count, wing = -1, pvalid_count;
594 int a_cue, d_cue, cue_init = 0, cargo = 0, base_ship, base_player, pship = -1;
595 int no_arrival_warp = 0, no_departure_warp = 0, escort_count, ship_orders, current_orders;
596 int pship_count; // a total count of the player ships not marked
600 CComboBox *box, *departure_box;
601 CSingleLock sync(&CS_update);
603 nprintf(("Fred routing", "Ship dialog load\n"));
604 if (!GetSafeHwnd() || bypass_all)
607 sync.Lock(); // don't initialize if we are still updating. Wait until update is done.
609 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
610 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
612 departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
613 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
615 if (The_mission.game_type & MISSION_TYPE_MULTI){
616 mission_type = 0; // multi player mission
618 mission_type = 1; // non-multiplayer mission (implies single player mission I guess)
621 // figure out what all we are editing.
622 ship_count = player_count = escort_count = pship_count = pvalid_count = 0;
623 base_ship = base_player = -1;
624 enable = p_enable = 1;
625 objp = GET_FIRST(&obj_used_list);
626 while (objp != END_OF_LIST(&obj_used_list)) {
627 if ((objp->type == OBJ_SHIP) && (Ships[objp->instance].flags & SF_ESCORT)){
628 escort_count++; // get a total count of escort ships
631 if (objp->type == OBJ_START){
632 pship_count++; // count all player starts in mission
635 if (objp->flags & OF_MARKED) {
637 if ((type == OBJ_START) && !mission_type){ // in multiplayer missions, starts act like ships
642 if (type == OBJ_START) {
644 // if player_count is 1, base_player will be the one and only player
645 i = base_player = objp->instance;
647 } else if (type == OBJ_SHIP) {
649 // if ship_count is 1, base_ship will be the one and only ship
650 i = base_ship = objp->instance;
654 if (Ship_info[Ships[i].ship_info_index].flags & SIF_PLAYER_SHIP){
660 objp = GET_NEXT(objp);
663 total_count = ship_count + player_count; // get total number of objects being edited.
664 if (total_count > 1){
671 m_arrival_location = -1;
672 m_arrival_dist.blank();
673 m_arrival_target = -1;
674 m_arrival_delay.blank();
675 m_departure_location = -1;
676 m_departure_target = -1;
677 m_departure_delay.blank();
679 player_ship = single_ship = -1;
680 m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
681 select_sexp_node = -1;
682 ship_orders = 0; // assume they are all the same type
684 box = (CComboBox *) GetDlgItem(IDC_SHIP_CARGO1);
686 for (i=0; i<Num_cargo; i++){
687 box->AddString(Cargo_names[i]);
691 Assert((ship_count == 1) && (base_ship >= 0));
692 m_ship_name = Ships[base_ship].ship_name;
694 m_ship_name = _T("");
697 m_update_arrival = m_update_departure = 1;
699 objp = GET_FIRST(&obj_used_list);
700 while (objp != END_OF_LIST(&obj_used_list)) {
701 if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) {
702 if (objp->flags & OF_MARKED) {
703 // do processing for both ships and players
704 i = get_ship_from_obj(objp);
705 if (base_player >= 0) {
706 m_ship_class = Ships[i].ship_info_index;
707 m_team = bitmask_2_bitnum(Ships[i].team);
708 pship = (objp->type == OBJ_START) ? 1 : 0;
712 if (Ships[i].ship_info_index != m_ship_class)
714 if (bitmask_2_bitnum(Ships[i].team) != m_team)
717 pship = tristate_set(Objects[Ships[i].objnum].type == OBJ_START, pship);
720 // 'and' in the ship type of this ship to our running bitfield
721 current_orders = ship_get_default_orders_accepted( &Ship_info[Ships[i].ship_info_index] );
723 ship_orders = current_orders;
724 } else if (ship_orders != current_orders){
728 if (Ships[i].flags & SF_ESCORT){
729 escort_count--; // remove marked escorts from count
732 if (Objects[Ships[i].objnum].type == OBJ_START){
733 pship_count--; // removed marked starts from count
736 // do processing only for ships (plus players if in a multiplayer mission
737 if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) {
738 // process this if ship not in a wing
739 if (Ships[i].wingnum < 0) {
742 a_cue = Ships[i].arrival_cue;
743 d_cue = Ships[i].departure_cue;
744 m_arrival_location = Ships[i].arrival_location;
745 m_arrival_dist.init(Ships[i].arrival_distance);
746 m_arrival_target = Ships[i].arrival_anchor;
747 m_arrival_delay.init(Ships[i].arrival_delay);
748 m_departure_location = Ships[i].departure_location;
749 m_departure_delay.init(Ships[i].departure_delay);
750 m_departure_target = Ships[i].departure_anchor;
754 if (Ships[i].arrival_location != m_arrival_location){
755 m_arrival_location = -1;
758 if (Ships[i].departure_location != m_departure_location){
759 m_departure_location = -1;
762 m_arrival_dist.set(Ships[i].arrival_distance);
763 m_arrival_delay.set(Ships[i].arrival_delay);
764 m_departure_delay.set(Ships[i].departure_delay);
766 if (Ships[i].arrival_anchor != m_arrival_target){
767 m_arrival_target = -1;
770 if (!cmp_sexp_chains(a_cue, Ships[i].arrival_cue)) {
772 m_update_arrival = 0;
775 if (!cmp_sexp_chains(d_cue, Ships[i].departure_cue)) {
777 m_update_departure = 0;
780 if ( Ships[i].departure_anchor != m_departure_target ){
781 m_departure_target = -1;
786 // process the first ship in group, else process the rest
787 if (base_ship >= 0) {
788 m_ai_class = Ships[i].weapons.ai_class;
789 cargo = Ships[i].cargo1;
790 m_cargo1 = Cargo_names[cargo];
791 m_hotkey = Ships[i].hotkey + 1;
792 m_score.init(Ships[i].score);
794 m_persona = Ships[i].persona_index + 1;
796 // we use final_death_time member of ship structure for holding the amount of time before a mission
797 // to destroy this ship
798 wing = Ships[i].wingnum;
800 GetDlgItem(IDC_WING) -> SetWindowText("None");
803 GetDlgItem(IDC_WING) -> SetWindowText(Wings[wing].name);
804 if (!query_whole_wing_marked(wing))
805 m_update_arrival = m_update_departure = 0;
808 // set routine local varaiables for ship/object flags
809 no_arrival_warp = (Ships[i].flags & SF_NO_ARRIVAL_WARP) ? 1 : 0;
810 no_departure_warp = (Ships[i].flags & SF_NO_DEPARTURE_WARP) ? 1 : 0;
817 if (Ships[i].weapons.ai_class != m_ai_class){
821 if (Ships[i].cargo1 != cargo){
825 m_score.set(Ships[i].score);
827 if (Ships[i].hotkey != m_hotkey - 1){
831 if ( Ships[i].persona_index != (m_persona-1) ){
835 if (Ships[i].wingnum != wing){
836 GetDlgItem(IDC_WING) -> SetWindowText("");
839 no_arrival_warp = tristate_set(Ships[i].flags & SF_NO_ARRIVAL_WARP, no_arrival_warp);
840 no_departure_warp = tristate_set(Ships[i].flags & SF_NO_DEPARTURE_WARP, no_departure_warp);
846 objp = GET_NEXT(objp);
850 m_arrival_tree.clear_tree("");
851 m_departure_tree.clear_tree("");
855 m_arrival_tree.load_tree(a_cue);
856 m_departure_tree.load_tree(d_cue, "false");
859 m_arrival_tree.clear_tree();
860 m_arrival_tree.DeleteAllItems();
861 m_departure_tree.clear_tree();
862 m_departure_tree.DeleteAllItems();
865 m_player_ship.SetCheck(pship);
866 m_no_arrival_warp.SetCheck(no_arrival_warp);
867 m_no_departure_warp.SetCheck(no_departure_warp);
870 i = m_arrival_tree.select_sexp_node;
872 w = GetDlgItem(IDC_ARRIVAL_TREE);
873 m_arrival_tree.hilite_item(i);
876 i = m_departure_tree.select_sexp_node;
878 w = GetDlgItem(IDC_DEPARTURE_TREE);
879 m_departure_tree.hilite_item(i);
884 } else { // no ships selected, 0 or more player ships selected
885 if (player_count > 1) { // multiple player ships selected
886 Assert(base_player >= 0);
887 m_ship_name = _T("");
888 m_player_ship.SetCheck(TRUE);
889 objp = GET_FIRST(&obj_used_list);
890 while (objp != END_OF_LIST(&obj_used_list)) {
891 if ((objp->type == OBJ_START) && (objp->flags & OF_MARKED)) {
893 if (base_player >= 0) {
894 m_ship_class = Ships[i].ship_info_index;
895 m_team = bitmask_2_bitnum(Ships[i].team);
899 if (Ships[i].ship_info_index != m_ship_class)
901 if (bitmask_2_bitnum(Ships[i].team) != m_team)
906 objp = GET_NEXT(objp);
909 // only 1 player selected..
910 } else if (query_valid_object() && (Objects[cur_object_index].type == OBJ_START)) {
911 Assert((player_count == 1) && !multi_edit);
912 player_ship = Objects[cur_object_index].instance;
913 m_ship_name = Ships[player_ship].ship_name;
914 m_ship_class = Ships[player_ship].ship_info_index;
915 m_team = bitmask_2_bitnum(Ships[player_ship].team);
916 m_player_ship.SetCheck(TRUE);
918 } else { // no ships or players selected..
919 m_ship_name = _T("");
923 m_player_ship.SetCheck(FALSE);
929 m_score.blank(); // cause control to be blank
930 m_arrival_location = -1;
931 m_departure_location = -1;
932 m_arrival_delay.blank();
933 m_departure_delay.blank();
934 m_arrival_dist.blank();
935 m_arrival_target = -1;
936 m_departure_target = -1;
937 m_arrival_tree.clear_tree();
938 m_arrival_tree.DeleteAllItems();
939 m_departure_tree.clear_tree();
940 m_departure_tree.DeleteAllItems();
941 m_no_arrival_warp.SetCheck(0);
942 m_no_departure_warp.SetCheck(0);
943 enable = p_enable = 0;
944 GetDlgItem(IDC_WING)->SetWindowText(_T("None"));
947 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
948 // must put the appropriate ships into the list depending on arrival location
949 if ( m_arrival_location != ARRIVE_FROM_DOCK_BAY ){
950 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
952 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
955 // set the internal variable appropriatly
956 if (m_arrival_target >= SPECIAL_ARRIVAL_ANCHORS_OFFSET){
957 m_arrival_target -= SPECIAL_ARRIVAL_ANCHORS_OFFSET;
958 } else if (m_arrival_target >= 0) {
959 m_arrival_target = box->FindStringExact(-1, Ships[m_arrival_target].ship_name);
962 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
963 // must put the appropriate ships into the list depending on departure location
964 if ( m_departure_location == DEPART_AT_DOCK_BAY ){
965 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
970 if ( m_departure_target >= 0 ){
971 m_departure_target = box->FindStringExact( -1, Ships[m_departure_target].ship_name );
976 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
977 if (!mission_type){ // multiplayer mission
978 box->EnableWindow(TRUE);
982 box->EnableWindow(FALSE);
987 for (i=0; i<2; i++) // hard coded: only allow friendly and hostile
988 box->AddString(Team_names[i]);
990 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
991 box->EnableWindow(enable);
993 for (i=0; i<Num_team_names; i++){
994 box->AddString(Team_names[i]);
999 m_arrival_dist.display();
1000 m_arrival_delay.display();
1001 m_departure_delay.display();
1007 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(FALSE);
1008 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(FALSE);
1009 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1010 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1011 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(FALSE);
1012 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(FALSE);
1013 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(FALSE);
1014 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1015 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(FALSE);
1016 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(FALSE);
1017 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(FALSE);
1018 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(FALSE);
1019 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(FALSE);
1022 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable);
1023 if (m_arrival_location) {
1024 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable);
1025 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable);
1027 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1028 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1031 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1032 if ( m_departure_location ) {
1033 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
1035 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1038 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(enable);
1039 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(enable);
1040 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
1041 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1042 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable);
1043 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable);
1044 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable);
1045 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable);
1046 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable);
1050 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(!multi_edit);
1051 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(TRUE);
1052 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
1053 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(TRUE);
1054 GetDlgItem(IDC_WEAPONS)->EnableWindow(m_ship_class >= 0);
1055 GetDlgItem(IDC_FLAGS)->EnableWindow(TRUE);
1058 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(FALSE);
1059 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(FALSE);
1060 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
1061 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(FALSE);
1062 GetDlgItem(IDC_WEAPONS)->EnableWindow(FALSE);
1063 GetDlgItem(IDC_FLAGS)->EnableWindow(FALSE);
1066 GetDlgItem(IDC_AI_CLASS)->EnableWindow(enable);
1067 GetDlgItem(IDC_SHIP_CARGO1)->EnableWindow(enable);
1068 GetDlgItem(IDC_HOTKEY)->EnableWindow(enable);
1069 if ((m_ship_class >= 0) && !(Ship_info[m_ship_class].flags & SIF_CARGO) && !(Ship_info[m_ship_class].flags & SIF_NO_SHIP_TYPE))
1070 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1071 else if (multi_edit)
1072 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1074 GetDlgItem(IDC_GOALS)->EnableWindow(FALSE);
1076 // !pship_count used because if allowed to clear, we would have no player starts
1077 if (mission_type || !pship_count || (pship_count + total_count > MAX_PLAYERS) || (pvalid_count < total_count))
1078 m_player_ship.EnableWindow(FALSE);
1080 m_player_ship.EnableWindow(TRUE);
1082 GetDlgItem(IDC_DELETE_SHIP)->EnableWindow(enable);
1083 GetDlgItem(IDC_SHIP_RESET)->EnableWindow(enable);
1084 GetDlgItem(IDC_SCORE)->EnableWindow(enable);
1087 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(m_ship_class >= 0);
1089 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(0);
1090 GetDlgItem(IDC_SHIP_TBL)->ShowWindow(SW_HIDE);
1093 if (cue_init > 1) { // more than one ship (players don't have cues to edit)
1094 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_SHOW);
1095 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_SHOW);
1098 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_HIDE);
1099 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_HIDE);
1102 if (multi_edit || (total_count > 1)) {
1103 // we will allow the ignore orders dialog to be multi edit if all selected
1104 // ships are the same type. the ship_type (local) variable holds the ship types
1105 // for all ships. Determine how may bits set and enable/diable window
1107 if ( /*(m_team == -1) ||*/ (ship_orders == -1) ){
1108 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(FALSE);
1110 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(TRUE);
1113 // always enabled when one ship is selected
1114 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(enable);
1116 // always enabled if >= 1 ship selected
1117 GetDlgItem(IDC_SHIP_PERSONA)->EnableWindow(enable);
1120 SetWindowText("Edit Marked Ships");
1121 } else if (player_count) {
1122 SetWindowText("Edit Player Ship");
1124 SetWindowText("Edit Ship");
1127 // setup alternate name stuff
1128 if(player_ship >= 0){
1129 ship_alt_name_init(player_ship);
1131 ship_alt_name_init(single_ship);
1140 // update ship structure(s) with dialog data. The data is first checked for errors. If
1141 // no errors occur, returns 0. If an error occurs, returns -1. If the update is bypassed,
1142 // returns 1. Bypass is necessary to avoid an infinite loop, and it doesn't actually
1143 // update the data. Bypass only occurs if bypass mode is active and we still get an error.
1144 // Once the error no longer occurs, bypass mode is cleared and data is updated.
1145 int CShipEditorDlg::update_data(int redraw)
1147 char *str, old_name[255];
1150 CSingleLock sync(&CS_cur_object_index), sync2(&CS_update);
1152 nprintf(("Fred routing", "Ship dialog save\n"));
1153 if (!GetSafeHwnd() || !initialized || bypass_all)
1156 sync.Lock(); // don't allow cur_object_index to change while we are using it
1157 sync2.Lock(); // don't allow reinitialization until we are done updating
1160 Wing_editor_dialog.update_data_safe();
1161 if (multi_edit) { // editing multiple ships (ships and/or players)
1162 ptr = GET_FIRST(&obj_used_list);
1163 while (ptr != END_OF_LIST(&obj_used_list)) {
1164 if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags & OF_MARKED))
1165 update_ship(get_ship_from_obj(ptr));
1167 ptr = GET_NEXT(ptr);
1170 } else if (player_ship >= 0) { // editing a single player
1171 update_ship(player_ship);
1173 } else if (single_ship >= 0) { // editing a single ship
1174 ptr = GET_FIRST(&obj_used_list);
1175 while (ptr != END_OF_LIST(&obj_used_list)) {
1176 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (cur_object_index != OBJ_INDEX(ptr))) {
1177 str = Ships[ptr->instance].ship_name;
1178 if (!stricmp(m_ship_name, str)) {
1183 z = MessageBox("This ship name is already being used by another ship\n"
1184 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1189 m_ship_name = _T(Ships[single_ship].ship_name);
1194 ptr = GET_NEXT(ptr);
1197 for (i=0; i<MAX_WINGS; i++)
1198 if (Wings[i].wave_count && !stricmp(Wings[i].name, m_ship_name)) {
1203 z = MessageBox("This ship name is already being used by a wing\n"
1204 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1209 m_ship_name = _T(Ships[single_ship].ship_name);
1213 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
1214 if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_ship_name)) {
1219 z = MessageBox("This ship name is already being used by a waypoint path\n"
1220 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1225 m_ship_name = _T(Ships[single_ship].ship_name);
1229 for (i=0; i<Num_jump_nodes; i++)
1230 if (!stricmp(Jump_nodes[i].name, m_ship_name)) {
1235 z = MessageBox("This ship name is already being used by a jump node\n"
1236 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1241 m_ship_name = _T(Ships[single_ship].ship_name);
1245 wing = Ships[single_ship].wingnum;
1247 Assert((wing < MAX_WINGS) && Wings[wing].wave_count);
1248 for (i=0; i<Wings[wing].wave_count; i++)
1249 if (wing_objects[wing][i] == Ships[single_ship].objnum)
1252 Assert(i < Wings[wing].wave_count);
1253 sprintf(old_name, "%s %d", Wings[wing].name, i + 1);
1254 if (stricmp(old_name, m_ship_name)) {
1258 if (MessageBox("This ship is part of a wing, and it's name cannot be changed",
1259 NULL, MB_OKCANCEL) == IDCANCEL)
1262 m_ship_name = _T(old_name);
1267 z = update_ship(single_ship);
1271 strcpy(old_name, Ships[single_ship].ship_name);
1272 string_copy(Ships[single_ship].ship_name, m_ship_name, NAME_LENGTH, 1);
1273 str = Ships[single_ship].ship_name;
1274 if (stricmp(old_name, str)) {
1275 update_sexp_references(old_name, str);
1276 ai_update_goal_references(REF_TYPE_SHIP, old_name, str);
1277 for (i=0; i<Num_reinforcements; i++)
1278 if (!stricmp(old_name, Reinforcements[i].name)) {
1279 Assert(strlen(str) < NAME_LENGTH);
1280 strcpy(Reinforcements[i].name, str);
1287 if (Player_start_shipnum < 0 || Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) { // need a new single player start.
1288 ptr = GET_FIRST(&obj_used_list);
1289 while (ptr != END_OF_LIST(&obj_used_list)) {
1290 if (ptr->type == OBJ_START) {
1291 Player_start_shipnum = ptr->instance;
1295 ptr = GET_NEXT(ptr);
1302 Wing_editor_dialog.initialize_data_safe(1);
1307 update_map_window();
1312 int CShipEditorDlg::update_ship(int ship)
1319 // THIS DIALOG IS THE SOME OF THE WORST CODE I HAVE EVER SEEN IN MY ENTIRE LIFE.
1320 // IT TOOK A RIDICULOUSLY LONG AMOUNT OF TIME TO ADD 2 FUNCTIONS. OMG
1321 ship_alt_name_close(ship);
1323 if ((Ships[ship].ship_info_index != m_ship_class) && (m_ship_class != -1)) {
1324 change_ship_type(ship, m_ship_class);
1329 MODIFY(Ships[ship].team, 1 << m_team);
1331 if (Objects[Ships[ship].objnum].type != OBJ_SHIP){
1332 if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)){
1337 if (m_ai_class != -1){
1338 MODIFY(Ships[ship].weapons.ai_class, m_ai_class);
1340 if (strlen(m_cargo1)) {
1341 z = string_lookup(m_cargo1, Cargo_names, Num_cargo);
1343 Assert(Num_cargo < MAX_CARGO);
1345 strcpy(Cargo_names[z], m_cargo1);
1348 MODIFY(Ships[ship].cargo1, (char)z);
1351 m_score.save(&Ships[ship].score);
1352 if (m_arrival_location != -1)
1353 MODIFY(Ships[ship].arrival_location, m_arrival_location);
1354 if (m_departure_location != -1)
1355 MODIFY(Ships[ship].departure_location, m_departure_location);
1357 // do the persona update
1358 // m_persona holds the index into the list. Get the item data associated with this index and then
1359 // assign to the ship taking care that we check for the NO_PERSONA_INDEX id
1360 box = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
1361 persona = box->GetItemData(m_persona);
1362 if ( persona == NO_PERSONA_INDEX )
1365 MODIFY(Ships[ship].persona_index, persona);
1367 if (Ships[ship].wingnum < 0) {
1368 if (!multi_edit || m_update_arrival) { // should we update the arrival cue?
1369 if (Ships[ship].arrival_cue >= 0)
1370 free_sexp2(Ships[ship].arrival_cue);
1372 Ships[ship].arrival_cue = m_arrival_tree.save_tree();
1375 if (!multi_edit || m_update_departure) {
1376 if (Ships[ship].departure_cue >= 0)
1377 free_sexp2(Ships[ship].departure_cue);
1379 Ships[ship].departure_cue = m_departure_tree.save_tree();
1382 m_arrival_dist.save(&Ships[ship].arrival_distance);
1383 m_arrival_delay.save(&Ships[ship].arrival_delay);
1384 m_departure_delay.save(&Ships[ship].departure_delay);
1385 if (m_arrival_target >= 0) {
1386 z = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
1387 MODIFY(Ships[ship].arrival_anchor, z);
1389 // if the arrival is not hyperspace or docking bay -- force arrival distance to be
1390 // greater than 2*radius of target.
1391 if (((m_arrival_location != ARRIVE_FROM_DOCK_BAY) && (m_arrival_location != ARRIVE_AT_LOCATION)) && (z >= 0) && (z < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
1392 d = int(min(500, 2.0f * Objects[Ships[ship].objnum].radius));
1393 if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) {
1394 str.Format("Ship must arrive at least %d meters away from target.\n"
1395 "Value has been reset to this. Use with caution!\r\n"
1396 "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[ship].objnum].radius) );
1399 if (Ships[ship].arrival_distance < 0)
1400 Ships[ship].arrival_distance = -d;
1402 Ships[ship].arrival_distance = d;
1404 m_arrival_dist.fix(Ships[ship].arrival_distance);
1408 z = ((CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
1409 MODIFY(Ships[ship].departure_anchor, z );
1413 MODIFY(Ships[ship].hotkey, m_hotkey - 1);
1415 switch( m_no_arrival_warp.GetCheck() ) {
1417 if (Ships[ship].flags & SF_NO_ARRIVAL_WARP)
1420 Ships[ship].flags &= ~SF_NO_ARRIVAL_WARP;
1424 if (!(Ships[ship].flags & SF_NO_ARRIVAL_WARP))
1427 Ships[ship].flags |= SF_NO_ARRIVAL_WARP;
1431 switch( m_no_departure_warp.GetCheck() ) {
1433 if (Ships[ship].flags & SF_NO_DEPARTURE_WARP)
1436 Ships[ship].flags &= ~SF_NO_DEPARTURE_WARP;
1440 if (!(Ships[ship].flags & SF_NO_DEPARTURE_WARP))
1443 Ships[ship].flags |= SF_NO_DEPARTURE_WARP;
1447 switch (m_player_ship.GetCheck()) {
1449 if (Objects[Ships[ship].objnum].type != OBJ_START) {
1454 Objects[Ships[ship].objnum].type = OBJ_START;
1458 if (Objects[Ships[ship].objnum].type == OBJ_START) {
1463 Objects[Ships[ship].objnum].type = OBJ_SHIP;
1471 void CShipEditorDlg::OnOK()
1479 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
1484 void CShipEditorDlg::OnInitMenu(CMenu *pMenu)
1488 m = pMenu->GetSubMenu(0);
1490 generate_ship_popup_menu(m, ID_SHIP_MENU, MF_ENABLED, SHIP_FILTER_PLAYERS);
1492 m->CheckMenuItem(ID_SHIP_MENU + cur_ship, MF_BYCOMMAND | MF_CHECKED);
1494 CWnd::OnInitMenu(pMenu);
1497 BOOL CShipEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam)
1501 id = LOWORD(wParam);
1502 if (id >= ID_SHIP_MENU && id < ID_SHIP_MENU + MAX_SHIPS) {
1503 if (!update_data()) {
1504 ship = id - ID_SHIP_MENU;
1506 set_cur_object_index(Ships[ship].objnum);
1511 return CDialog::OnCommand(wParam, lParam);
1514 void CShipEditorDlg::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1516 m_arrival_tree.right_clicked();
1520 void CShipEditorDlg::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1522 m_departure_tree.right_clicked();
1526 void CShipEditorDlg::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1528 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1530 if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1532 modified = editing = 1;
1538 void CShipEditorDlg::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1540 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1542 if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1544 modified = editing = 1;
1550 void CShipEditorDlg::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1552 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1554 *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1558 void CShipEditorDlg::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1560 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1562 *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1566 int CShipEditorDlg::verify()
1568 nprintf(("Fred routing", "Ship dialog verify\n"));
1569 if (!GetSafeHwnd() || !modified)
1578 void CShipEditorDlg::OnGoals()
1580 ShipGoalsDlg dlg_goals;
1582 Assert(query_valid_object());
1584 // dlg_goals.initialize_multi();
1587 // Assert(single_ship != -1);
1588 // dlg_goals.self_ship = single_ship;
1589 // dlg_goals.initialize(Ai_info[Ships[single_ship].ai_index].goals);
1593 Assert(single_ship != -1);
1594 dlg_goals.self_ship = single_ship;
1597 dlg_goals.DoModal();
1598 if (!multi_edit && !query_initial_orders_empty(Ai_info[Ships[single_ship].ai_index].goals))
1599 if ((Ships[single_ship].wingnum >= 0) && (query_initial_orders_conflict(Ships[single_ship].wingnum)))
1600 MessageBox("This ship's wing also has initial orders", "Possible conflict");
1603 void CShipEditorDlg::OnSelchangeShipClass()
1609 ptr = GET_FIRST(&obj_used_list);
1610 while (ptr != END_OF_LIST(&obj_used_list)) {
1611 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags & OF_MARKED))
1612 if (Ships[ptr->instance].ship_info_index != m_ship_class) {
1613 change_ship_type(ptr->instance, m_ship_class);
1617 ptr = GET_NEXT(ptr);
1620 update_map_window();
1623 void CShipEditorDlg::OnInitialStatus()
1627 dlg.m_multi_edit = multi_edit;
1631 void CShipEditorDlg::OnWeapons()
1634 WeaponEditorDlg dlg;
1638 dlg.m_multi_edit = multi_edit;
1642 objp = GET_FIRST(&obj_used_list);
1643 while (objp != END_OF_LIST(&obj_used_list)) {
1644 if (objp->flags & OF_MARKED)
1645 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
1648 if (Ships[i].weapons.ai_class != Ships[ship].weapons.ai_class)
1653 m_ai_class = Ships[i].weapons.ai_class;
1657 objp = GET_NEXT(objp);
1666 m_ai_class = Ships[ship].weapons.ai_class;
1669 box = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
1670 box->SetCurSel(m_ai_class);
1673 void CShipEditorDlg::OnShipReset()
1675 int i, j, index, ship;
1680 model_subsystem *sp;
1682 m_cargo1 = "Nothing";
1683 m_ai_class = AI_DEFAULT_CLASS;
1685 if (Ship_info[m_ship_class].species == SPECIES_SHIVAN)
1686 m_team = TEAM_HOSTILE;
1688 m_team = TEAM_FRIENDLY;
1691 objp = GET_FIRST(&obj_used_list);
1692 while (objp != END_OF_LIST(&obj_used_list)) {
1693 if (((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) && (objp->flags & OF_MARKED)) {
1694 ship = objp->instance;
1697 for (i=0; i<MAX_AI_GOALS; i++){
1698 Ai_info[Ships[ship].ai_index].goals[i].ai_mode = AI_GOAL_NONE;
1701 objp->phys_info.speed = 0.0f;
1702 objp->shields[0] = 100.0f;
1703 objp->hull_strength = 100.0f;
1705 sip = &Ship_info[Ships[ship].ship_info_index];
1706 for (i=0; i<sip->num_primary_banks; i++)
1707 Ships[ship].weapons.primary_bank_weapons[i] = sip->primary_bank_weapons[i];
1709 for (i=0; i<sip->num_secondary_banks; i++) {
1710 Ships[ship].weapons.secondary_bank_weapons[i] = sip->secondary_bank_weapons[i];
1711 Ships[ship].weapons.secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i];
1715 ptr = GET_FIRST(&Ships[ship].subsys_list);
1716 while (ptr != END_OF_LIST(&Ships[ship].subsys_list)) {
1717 ptr->current_hits = 0.0f;
1718 if (ptr->system_info->type == SUBSYSTEM_TURRET) {
1720 sp = &Ship_info[Ships[ship].ship_info_index].subsystems[index];
1723 for (i=0; i<MAX_PRIMARY_BANKS; i++){
1724 if (sp->primary_banks[i] != -1){
1725 wp->primary_bank_weapons[j++] = sp->primary_banks[i];
1729 wp->num_primary_banks = j;
1731 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1732 if (sp->secondary_banks[i] != -1) {
1733 wp->secondary_bank_weapons[j] = sp->secondary_banks[i];
1734 wp->secondary_bank_capacity[j++] = sp->secondary_bank_capacity[i];
1738 wp->num_secondary_banks = j;
1739 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1740 wp->secondary_bank_ammo[i] = 100;
1745 ptr = GET_NEXT(ptr);
1749 objp = GET_NEXT(objp);
1754 MessageBox("Ships reset to ship class defaults");
1756 MessageBox("Ship reset to ship class defaults");
1760 void CShipEditorDlg::OnDeleteShip()
1766 void CShipEditorDlg::OnShipTbl()
1770 dlg.set(m_ship_class);
1774 int CShipEditorDlg::make_ship_list(int *arr)
1779 ptr = GET_FIRST(&obj_used_list);
1780 while (ptr != END_OF_LIST(&obj_used_list)) {
1781 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)){
1782 arr[n++] = OBJ_INDEX(ptr);
1785 ptr = GET_NEXT(ptr);
1791 void CShipEditorDlg::OnPrev()
1793 int i, n, arr[MAX_SHIPS];
1795 if (!update_data()) {
1796 n = make_ship_list(arr);
1806 for (i=0; i<n; i++){
1807 if (Ships[cur_ship].objnum == arr[i]){
1820 set_cur_object_index(arr[i]);
1821 Ship_editor_dialog.initialize_data(1);
1828 void CShipEditorDlg::OnNext()
1830 int i, n, arr[MAX_SHIPS];
1832 if (!update_data()) {
1833 n = make_ship_list(arr);
1842 if (Ships[cur_ship].objnum == arr[i])
1852 set_cur_object_index(arr[i]);
1853 Ship_editor_dialog.initialize_data(1);
1860 void CShipEditorDlg::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1864 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1865 h = pNMTreeView->itemNew.hItem;
1867 m_arrival_tree.update_help(h);
1873 void CShipEditorDlg::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1877 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1878 h = pNMTreeView->itemNew.hItem;
1880 m_departure_tree.update_help(h);
1886 void CShipEditorDlg::calc_cue_height()
1890 GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1891 cue_height = cue.bottom - cue.top + 10;
1892 if (Show_sexp_help){
1893 cue_height += SEXP_HELP_BOX_SIZE;
1896 if (Hide_ship_cues) {
1897 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1902 void CShipEditorDlg::show_hide_sexp_help()
1906 if (Show_sexp_help){
1907 cue_height += SEXP_HELP_BOX_SIZE;
1909 cue_height -= SEXP_HELP_BOX_SIZE;
1912 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()){
1916 GetWindowRect(rect);
1918 if (Show_sexp_help){
1919 rect.bottom += SEXP_HELP_BOX_SIZE;
1921 rect.bottom -= SEXP_HELP_BOX_SIZE;
1927 void CShipEditorDlg::OnHideCues()
1931 GetWindowRect(rect);
1932 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1933 rect.bottom -= cue_height;
1937 rect.bottom += cue_height;
1944 void CShipEditorDlg::OnSelchangeArrivalLocation()
1949 box = (CComboBox *)GetDlgItem( IDC_ARRIVAL_TARGET );
1950 if (m_arrival_location) {
1951 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE);
1952 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE);
1953 if (m_arrival_target < 0) {
1954 m_arrival_target = 0;
1957 // determine which items we should put into the arrival target combo box
1958 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
1959 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1961 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1965 m_arrival_target = -1;
1966 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1967 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1972 void CShipEditorDlg::OnSelchangeDepartureLocation()
1977 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1978 if ( m_departure_location ) {
1979 box->EnableWindow(TRUE);
1980 if ( m_departure_target < 0 ) {
1981 m_departure_target = 0;
1984 // we need to build up the list box content based on the departure type. When
1985 // from a docking bay, only show ships in the list which have them. Show all ships otherwise
1986 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
1987 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1989 // I think that this section is currently illegal
1994 m_departure_target = -1;
1995 box->EnableWindow(FALSE);
2001 void CShipEditorDlg::OnPlayerShip()
2003 if (m_player_ship.GetCheck() == 1)
2004 m_player_ship.SetCheck(0);
2006 m_player_ship.SetCheck(1);
2008 update_map_window();
2011 void CShipEditorDlg::OnNoArrivalWarp()
2013 if (m_no_arrival_warp.GetCheck() == 1)
2014 m_no_arrival_warp.SetCheck(0);
2016 m_no_arrival_warp.SetCheck(1);
2019 void CShipEditorDlg::OnNoDepartureWarp()
2021 if (m_no_departure_warp.GetCheck() == 1)
2022 m_no_departure_warp.SetCheck(0);
2024 m_no_departure_warp.SetCheck(1);
2028 // function to possibly warn user when he selects a hotkey which might be used for
2030 void CShipEditorDlg::OnSelchangeHotkey()
2036 set_num = m_hotkey-1; // use -1 since values associated with hotkey sets are 1 index based
2038 // the first three sets are generally reserved for player starting wings.
2039 if ( set_num < MAX_STARTING_WINGS ) {
2040 sprintf( buf, "This hotkey set should probably be reserved\nfor wing %s", Starting_wing_names[set_num] );
2041 MessageBox(buf, NULL, MB_OK);
2045 void CShipEditorDlg::OnFlags()
2049 dlg.setup(p_enable);
2053 void CShipEditorDlg::OnIgnoreOrders()
2055 // TODO: Add your control notification handler code here
2056 ignore_orders_dlg player_order_dlg;
2058 Assert(query_valid_object());
2061 if ( single_ship != -1 ){
2062 player_order_dlg.m_ship = single_ship;
2064 player_order_dlg.m_ship = player_ship;
2067 player_order_dlg.m_ship = -1;
2070 player_order_dlg.DoModal();
2073 void CShipEditorDlg::OnSpecialExp()
2075 // TODO: Add your control notification handler code here
2076 ShipSpecialDamage dlg;
2080 // alternate ship name stuff
2081 void CShipEditorDlg::ship_alt_name_init(int base_ship)
2084 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2092 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
2095 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
2097 // reset the combobox and add all relevant strings
2098 ptr->ResetContent();
2099 ptr->AddString("<none>");
2100 for(idx=0; idx<Mission_alt_type_count; idx++){
2101 ptr->AddString(Mission_alt_types[idx]);
2109 // otherwise look his stuff up
2110 if(strlen(Fred_alt_names[base_ship])){
2111 ptr->SelectString(0, Fred_alt_names[base_ship]);
2117 void CShipEditorDlg::ship_alt_name_close(int base_ship)
2120 char str[NAME_LENGTH+2] = "";
2122 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2133 // see if we have something besides "none" selected
2134 ptr->GetWindowText(cstr);
2135 if(cstr == CString("<none>")){
2137 strcpy(Fred_alt_names[base_ship], "");
2141 p = cstr.GetBuffer(0);
2147 // otherwise see if it already exists
2148 if(mission_parse_lookup_alt(str) >= 0){
2149 strcpy(Fred_alt_names[base_ship], str);
2154 // otherwise try and add it
2155 if(mission_parse_add_alt(str) >= 0){
2156 strcpy(Fred_alt_names[base_ship], str);
2161 // bad - couldn't add
2162 strcpy(Fred_alt_names[base_ship], "");
2163 MessageBox("Couldn't add new alternate type name. Already using too many!");