2 * $Logfile: /Freespace2/code/fred2/ShipEditorDlg.cpp $
7 * Single ship editing dialog
10 * Revision 1.2 2002/05/07 03:16:44 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:08 root
17 * 8 8/18/99 1:32p Andsager
18 * Mark Vasudan wingmen as such.
20 * 7 8/18/99 1:12p Andsager
21 * Allow ships to be assigned Vasudan persona (wingman 6)
23 * 6 8/16/99 10:52p Andsager
24 * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
26 * 5 8/11/99 9:27a Andsager
27 * Fix compile warning.
29 * 4 5/20/99 6:59p Dave
30 * Added alternate type names for ships. Changed swarm missile table
33 * 3 2/11/99 2:15p Andsager
34 * Add ship explosion modification to FRED
36 * 2 10/07/98 6:28p Dave
37 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
38 * Fred. Globalized mission and campaign file extensions. Removed Silent
39 * Threat specific code.
41 * 1 10/07/98 3:02p Dave
43 * 1 10/07/98 3:00p Dave
45 * 157 6/16/98 10:17a Hoffoss
46 * Fixed define that was backwards and no one caught before release (ya,
49 * 156 5/23/98 3:33p Hoffoss
50 * Removed unused code in reinforcements editor and make ships.tbl button
51 * in ship editor disappear in release build.
53 * 155 5/21/98 12:58a Hoffoss
54 * Fixed warnings optimized build turned up.
56 * 154 4/28/98 2:13p Hoffoss
57 * Added code to help keep invalid player ship types from existing in
60 * 153 4/24/98 2:57p Jim
63 * 152 4/22/98 11:55a Hoffoss
64 * Fixed bug with ship editor's hide cue button when sexp help is on at
67 * 151 4/16/98 5:59p Duncan
68 * Fixed bad assumption, apparently.
70 * 150 4/07/98 9:42a Allender
71 * put in persona combo box into ship editor. Removed code to assign
72 * personas based on message
74 * 149 3/30/98 1:15p Hoffoss
75 * Fixed bug with arrival/departure cue window size calculation. Wasn't
76 * working anymore after my changes to dialog initing at startup.
78 * 148 3/27/98 12:02p Sandeep
80 * 147 3/25/98 4:14p Hoffoss
81 * Split ship editor up into ship editor and a misc dialog, which tracks
84 * 146 3/21/98 7:36p Lawrance
85 * Move jump nodes to own lib.
87 * 145 3/16/98 8:27p Allender
88 * Fred support for two new AI flags -- kamikaze and no dynamic goals.
90 * 144 3/10/98 6:11p Hoffoss
91 * Added jump node renaming abilities to Fred.
93 * 143 3/09/98 4:30p Allender
94 * multiplayer secondary weapon changes. red-alert and cargo-known-delay
95 * sexpressions. Add time cargo revealed to ship structure
97 * 142 2/22/98 1:21a Hoffoss
98 * Disabled weapon editor if mutliple ship types marked.
100 * 141 2/17/98 12:07p Hoffoss
101 * Changed over to using SF_CARGO_REVEALED in fred.
103 * 140 2/17/98 11:42a Hoffoss
104 * Added support for hidden from sensors condition.
106 * 139 2/13/98 2:42p Duncan
107 * Fixed bug, moved line down where it needs to be because
108 * pre-initializations need to be done first.
110 * 138 2/10/98 1:42p Allender
111 * allow > MAX_ESCORT_SHIPS to be marked as escort ships
113 * 137 2/06/98 2:54p Hoffoss
114 * Fixed some bugs in dialog init, and cleared up some of the confusion
115 * about how it works by renaming some variables and adding comments.
117 * 136 2/06/98 10:48a Hoffoss
118 * Fixed bug with not being able to make ships players in multi mode
121 * 135 2/04/98 4:32p Allender
122 * support for multiple briefings and debriefings. Changes to mission
123 * type (now a bitfield). Bitfield defs for multiplayer modes
125 * 134 1/29/98 5:14p Hoffoss
126 * Added support for a SF_INVULNERABLE ship flag in Fred.
128 * 133 1/12/98 10:41a Allender
129 * fixed minor bug with ship editor and ignore orders dialog
131 * 132 12/05/97 4:07p Hoffoss
132 * Changed code to allow WHO_FROM type ship sources to only show flyable
135 * 131 11/24/97 2:31p Allender
136 * allow ignore orders dialog to be active for players
138 * 130 11/24/97 9:07a Allender
139 * ignore orders dialog should function as multi-edit now
141 * 129 11/22/97 4:17p Allender
142 * first pass of making ignore orders dialog multi edit
144 * 128 11/13/97 4:14p Allender
145 * automatic assignment of hotkeys for starting wings. Appripriate
146 * warnings when they are incorrectly used. hotkeys correctly assigned to
147 * ships/wing arriving after mission start
149 * 127 11/11/97 3:32p Johnson
150 * allender: Combo boxes need to have lists initialized before setting
151 * internal class variable for arrival/depature targets
153 * 126 11/11/97 2:13p Allender
154 * docking bay support for Fred and Freespace. Added hook to ai code for
155 * arrival/departure from dock bays. Fred support now sufficient.
157 * 125 11/10/97 10:13p Allender
158 * added departure anchor to Fred and Freespace in preparation for using
159 * docking bays. Functional in Fred, not in FreeSpace.
161 * 124 10/21/97 4:49p Allender
162 * added flags to Fred and FreeSpace to forgo warp effect (toggle in ship
165 * 123 10/14/97 5:33p Hoffoss
166 * Added Fred support (and fsm support) for the no_arrival_music flags in
169 * 122 9/18/97 10:49a Allender
170 * increment/decrement Player_start variable when making a ship a player
173 * 121 9/17/97 5:43p Hoffoss
174 * Added Fred support for new player start information.
176 * 120 9/16/97 9:41p Hoffoss
177 * Changed Fred code around to stop using Parse_player structure for
178 * player information, and use actual ships instead.
180 * 119 9/15/97 2:35p Hoffoss
181 * Fixed bug in Fred where a player ship and normal ship both marked
182 * clobbered each other's ship type in ship editor dialog.
184 * 118 9/09/97 10:29a Hoffoss
185 * Added support for neutral team, and fixed changes made to how team is
186 * used in ship structure.
188 * 117 9/09/97 9:27a Hoffoss
189 * Removed #Jason Hoffoss# comments from code. Code is already set up to
190 * handle the situation properly.
192 * 116 9/06/97 2:13p Mike
193 * Replace support for TEAM_NEUTRAL
195 * 115 9/04/97 5:35p Hoffoss
196 * Fixed arrival distance stuff.
198 * 114 9/04/97 5:04p Johnson
199 * Fixed bug with arrival target distance checking.
201 * 113 9/04/97 4:31p Hoffoss
202 * Fixed bug: Changed ship editor to not touch wing info (arrival or
203 * departure cues) to avoid conflicts with wing editor's changes.
205 * 112 8/30/97 9:52p Hoffoss
206 * Implemented arrival location, distance, and anchor in Fred.
208 * 111 8/28/97 8:56a Hoffoss
209 * Added more checking to sexp error checker, fixed some bugs.
211 * 110 8/25/97 5:56p Hoffoss
212 * Added multiple asteroid field support, loading and saving of asteroid
213 * fields, and ship score field to Fred.
215 * 109 8/22/97 4:16p Hoffoss
216 * added support for arrival and departure info in ship editor using
217 * wing's info if editing marked ships in a wing instead of using ship's.
219 * 108 8/21/97 11:37p Hoffoss
220 * Fixed bug: when renaming a ship that is a reinforcement, an extra
221 * instance of it is added to the reinforcement list.
223 * 107 8/20/97 6:53p Hoffoss
224 * Implemented escort flag support in Fred.
226 * 106 8/19/97 2:53p Hoffoss
227 * Fixed bug where multiple ships editing doesn't change players.
229 * 105 8/19/97 1:44p Hoffoss
230 * Fixed bug with updating too quickly (i.e. via prev and next buttons).
238 #include "fredview.h"
246 #include "management.h"
247 #include "linklist.h"
248 #include "initialstatus.h"
249 #include "weaponeditordlg.h"
251 #include "textviewdlg.h"
252 #include "player.h" // used for the max_keyed_target stuff
253 #include "ignoreordersdlg.h"
254 #include "missionparse.h"
256 #include "starfield.h"
257 #include "jumpnode.h"
258 #include "shipflagsdlg.h"
259 #include "missionmessage.h"
260 #include "shipspecialdamage.h"
262 #define ID_SHIP_MENU 9000
264 #define NO_PERSONA_INDEX 999
267 #define new DEBUG_NEW
269 static char THIS_FILE[] = __FILE__;
272 void numeric_edit_control::setup(int id, CWnd *wnd)
278 void numeric_edit_control::init(int n)
284 void numeric_edit_control::set(int n)
291 void numeric_edit_control::display()
296 str.Format("%d", value);
299 dlg->GetDlgItem(control_id)->SetWindowText(str);
302 void numeric_edit_control::save(int *n)
307 dlg->GetDlgItem(control_id)->GetWindowText(str);
309 MODIFY(*n, atoi(str));
314 void numeric_edit_control::fix(int n)
322 w = dlg->GetDlgItem(control_id);
323 dlg->GetDlgItem(control_id)->SetWindowText(str);
327 /////////////////////////////////////////////////////////////////////////////
328 // CShipEditorDlg dialog
330 CShipEditorDlg::CShipEditorDlg(CWnd* pParent /*=NULL*/)
331 : CDialog(CShipEditorDlg::IDD, pParent)
333 //{{AFX_DATA_INIT(CShipEditorDlg)
334 m_ship_name = _T("");
338 m_arrival_location = -1;
339 m_departure_location = -1;
342 m_update_arrival = FALSE;
343 m_update_departure = FALSE;
344 m_arrival_target = -1;
345 m_departure_target = -1;
350 initialized = editing = multi_edit = 0;
351 select_sexp_node = -1;
355 // Modeless constructor, MK
356 CShipEditorDlg::CShipEditorDlg(CView* pView)
359 initialized = editing = 0;
360 select_sexp_node = -1;
363 void CShipEditorDlg::DoDataExchange(CDataExchange* pDX)
368 CDialog::DoDataExchange(pDX);
369 //{{AFX_DATA_MAP(CShipEditorDlg)
370 DDX_Control(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp);
371 DDX_Control(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp);
372 DDX_Control(pDX, IDC_PLAYER_SHIP, m_player_ship);
373 DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin);
374 DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin);
375 DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree);
376 DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree);
377 DDX_Text(pDX, IDC_SHIP_NAME, m_ship_name);
378 DDX_CBString(pDX, IDC_SHIP_CARGO1, m_cargo1);
379 DDX_CBIndex(pDX, IDC_SHIP_CLASS, m_ship_class);
380 DDX_CBIndex(pDX, IDC_SHIP_TEAM, m_team);
381 DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location);
382 DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location);
383 DDX_CBIndex(pDX, IDC_AI_CLASS, m_ai_class);
384 DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey);
385 DDX_Check(pDX, IDC_UPDATE_ARRIVAL, m_update_arrival);
386 DDX_Check(pDX, IDC_UPDATE_DEPARTURE, m_update_departure);
387 DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target);
388 DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target);
389 DDX_CBIndex(pDX, IDC_SHIP_PERSONA, m_persona);
391 DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1);
392 DDV_MaxChars(pDX, m_cargo1, NAME_LENGTH - 1);
394 if (pDX->m_bSaveAndValidate) { // get dialog control values
395 GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str);
401 m_arrival_delay.init(n);
403 GetDlgItem(IDC_ARRIVAL_DISTANCE)->GetWindowText(str);
404 m_arrival_dist.init(atoi(str));
406 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
410 m_departure_delay.init(n);
412 GetDlgItem(IDC_SCORE)->GetWindowText(str);
413 m_score.init(atoi(str));
417 BEGIN_MESSAGE_MAP(CShipEditorDlg, CDialog)
418 //{{AFX_MSG_MAP(CShipEditorDlg)
420 ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree)
421 ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree)
422 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree)
423 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree)
424 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree)
425 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree)
426 ON_BN_CLICKED(IDC_GOALS, OnGoals)
427 ON_CBN_SELCHANGE(IDC_SHIP_CLASS, OnSelchangeShipClass)
428 ON_BN_CLICKED(IDC_INITIAL_STATUS, OnInitialStatus)
429 ON_BN_CLICKED(IDC_WEAPONS, OnWeapons)
430 ON_BN_CLICKED(IDC_SHIP_RESET, OnShipReset)
431 ON_BN_CLICKED(IDC_DELETE_SHIP, OnDeleteShip)
432 ON_BN_CLICKED(IDC_SHIP_TBL, OnShipTbl)
433 ON_BN_CLICKED(IDC_NEXT, OnNext)
434 ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree)
435 ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree)
436 ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues)
437 ON_BN_CLICKED(IDC_PREV, OnPrev)
438 ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation)
439 ON_BN_CLICKED(IDC_PLAYER_SHIP, OnPlayerShip)
440 ON_BN_CLICKED(IDC_NO_ARRIVAL_WARP, OnNoArrivalWarp)
441 ON_BN_CLICKED(IDC_NO_DEPARTURE_WARP, OnNoDepartureWarp)
442 ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation)
443 ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey)
444 ON_BN_CLICKED(IDC_FLAGS, OnFlags)
445 ON_BN_CLICKED(IDC_IGNORE_ORDERS, OnIgnoreOrders)
447 ON_BN_CLICKED(IDC_SPECIAL_EXP, OnSpecialExp)
451 /////////////////////////////////////////////////////////////////////////////
452 // CShipEditorDlg message handlers
454 BOOL CShipEditorDlg::Create()
460 r = CDialog::Create(IDD, Fred_main_wnd);
462 ptr = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
464 for (i=0; i<MAX_ARRIVAL_NAMES; i++){
465 ptr->AddString(Arrival_location_names[i]);
468 ptr = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
470 for (i=0; i<MAX_DEPARTURE_NAMES; i++){
471 ptr->AddString(Departure_location_names[i]);
474 ptr = (CComboBox *) GetDlgItem(IDC_SHIP_CLASS);
476 for (i=0; i<Num_ship_types; i++){
477 ptr->AddString(Ship_info[i].name);
480 ptr = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
482 for (i=0; i<Num_ai_classes; i++){
483 ptr->AddString(Ai_class_names[i]);
486 // alternate ship name combobox
487 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_ALT);
489 ptr->AddString("<none>");
492 // deal with the persona dialog
493 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
495 index = ptr->AddString("<None>");
497 ptr->SetItemData(index, NO_PERSONA_INDEX);
500 for ( i = 0; i < Num_personas; i++ ) {
501 if ( Personas[i].flags & PERSONA_FLAG_WINGMAN ) {
504 // don't bother putting any vasudan personas on the list -- done automatically by code
505 // if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
509 CString persona_name = Personas[i].name;
510 if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
511 persona_name += " -Vas";
514 index = ptr->AddString(persona_name);
516 ptr->SetItemData(index, i);
521 m_score.setup(IDC_SCORE, this);
522 m_arrival_dist.setup(IDC_ARRIVAL_DISTANCE, this);
523 m_arrival_delay.setup(IDC_ARRIVAL_DELAY, this);
524 m_departure_delay.setup(IDC_DEPARTURE_DELAY, this);
527 m_arrival_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog
528 m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
529 m_departure_tree.link_modified(&modified);
530 m_departure_tree.setup();
531 m_arrival_delay_spin.SetRange(0, 999);
532 m_departure_delay_spin.SetRange(0, 999);
538 // This gets called when you click on the "X" button. Note that OnClose
539 // does not destroy the window. It only hides it.
540 void CShipEditorDlg::OnClose()
542 if (verify() && (!bypass_errors)) {
543 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
549 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
554 SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
555 Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
558 BOOL CShipEditorDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
562 r = CDialog::Create(IDD, pParentWnd);
566 int CShipEditorDlg::tristate_set(int val, int cur_state)
582 // called to initialize the dialog box to reflect what ships we currently have marked. Any
583 // time what we have marked changes, this should get called again.
585 // Notes: player_count is the number of player starts marked, when we are in a non-multiplayer
586 // mission (NMM). In a multiplayer mission (MM), player_count will always be zero.
587 // ship_count in NMM is the number of ships (i.e. not player starts) that are marked. In MM,
588 // ship_count is the number of ships and player starts. Total_count is the sum of ship_count
589 // and player_count in all cases. The reason player_count isn't used in MM, and ship_count
590 // is used instead to track player starts is because in MM, player starts can be edited as
591 // freely as AI ships, and are very likely to be AI ships sometimes. Thus, treating them like
592 // AI ships instead of player starts simplifies processing.
594 void CShipEditorDlg::initialize_data(int full_update)
596 int i, type, ship_count, player_count, total_count, wing = -1, pvalid_count;
597 int a_cue, d_cue, cue_init = 0, cargo = 0, base_ship, base_player, pship = -1;
598 int no_arrival_warp = 0, no_departure_warp = 0, escort_count, ship_orders, current_orders;
599 int pship_count; // a total count of the player ships not marked
603 CComboBox *box, *departure_box;
604 CSingleLock sync(&CS_update);
606 nprintf(("Fred routing", "Ship dialog load\n"));
607 if (!GetSafeHwnd() || bypass_all)
610 sync.Lock(); // don't initialize if we are still updating. Wait until update is done.
612 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
613 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
615 departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
616 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
618 if (The_mission.game_type & MISSION_TYPE_MULTI){
619 mission_type = 0; // multi player mission
621 mission_type = 1; // non-multiplayer mission (implies single player mission I guess)
624 // figure out what all we are editing.
625 ship_count = player_count = escort_count = pship_count = pvalid_count = 0;
626 base_ship = base_player = -1;
627 enable = p_enable = 1;
628 objp = GET_FIRST(&obj_used_list);
629 while (objp != END_OF_LIST(&obj_used_list)) {
630 if ((objp->type == OBJ_SHIP) && (Ships[objp->instance].flags & SF_ESCORT)){
631 escort_count++; // get a total count of escort ships
634 if (objp->type == OBJ_START){
635 pship_count++; // count all player starts in mission
638 if (objp->flags & OF_MARKED) {
640 if ((type == OBJ_START) && !mission_type){ // in multiplayer missions, starts act like ships
645 if (type == OBJ_START) {
647 // if player_count is 1, base_player will be the one and only player
648 i = base_player = objp->instance;
650 } else if (type == OBJ_SHIP) {
652 // if ship_count is 1, base_ship will be the one and only ship
653 i = base_ship = objp->instance;
657 if (Ship_info[Ships[i].ship_info_index].flags & SIF_PLAYER_SHIP){
663 objp = GET_NEXT(objp);
666 total_count = ship_count + player_count; // get total number of objects being edited.
667 if (total_count > 1){
674 m_arrival_location = -1;
675 m_arrival_dist.blank();
676 m_arrival_target = -1;
677 m_arrival_delay.blank();
678 m_departure_location = -1;
679 m_departure_target = -1;
680 m_departure_delay.blank();
682 player_ship = single_ship = -1;
683 m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
684 select_sexp_node = -1;
685 ship_orders = 0; // assume they are all the same type
687 box = (CComboBox *) GetDlgItem(IDC_SHIP_CARGO1);
689 for (i=0; i<Num_cargo; i++){
690 box->AddString(Cargo_names[i]);
694 Assert((ship_count == 1) && (base_ship >= 0));
695 m_ship_name = Ships[base_ship].ship_name;
697 m_ship_name = _T("");
700 m_update_arrival = m_update_departure = 1;
702 objp = GET_FIRST(&obj_used_list);
703 while (objp != END_OF_LIST(&obj_used_list)) {
704 if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) {
705 if (objp->flags & OF_MARKED) {
706 // do processing for both ships and players
707 i = get_ship_from_obj(objp);
708 if (base_player >= 0) {
709 m_ship_class = Ships[i].ship_info_index;
710 m_team = bitmask_2_bitnum(Ships[i].team);
711 pship = (objp->type == OBJ_START) ? 1 : 0;
715 if (Ships[i].ship_info_index != m_ship_class)
717 if (bitmask_2_bitnum(Ships[i].team) != m_team)
720 pship = tristate_set(Objects[Ships[i].objnum].type == OBJ_START, pship);
723 // 'and' in the ship type of this ship to our running bitfield
724 current_orders = ship_get_default_orders_accepted( &Ship_info[Ships[i].ship_info_index] );
726 ship_orders = current_orders;
727 } else if (ship_orders != current_orders){
731 if (Ships[i].flags & SF_ESCORT){
732 escort_count--; // remove marked escorts from count
735 if (Objects[Ships[i].objnum].type == OBJ_START){
736 pship_count--; // removed marked starts from count
739 // do processing only for ships (plus players if in a multiplayer mission
740 if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) {
741 // process this if ship not in a wing
742 if (Ships[i].wingnum < 0) {
745 a_cue = Ships[i].arrival_cue;
746 d_cue = Ships[i].departure_cue;
747 m_arrival_location = Ships[i].arrival_location;
748 m_arrival_dist.init(Ships[i].arrival_distance);
749 m_arrival_target = Ships[i].arrival_anchor;
750 m_arrival_delay.init(Ships[i].arrival_delay);
751 m_departure_location = Ships[i].departure_location;
752 m_departure_delay.init(Ships[i].departure_delay);
753 m_departure_target = Ships[i].departure_anchor;
757 if (Ships[i].arrival_location != m_arrival_location){
758 m_arrival_location = -1;
761 if (Ships[i].departure_location != m_departure_location){
762 m_departure_location = -1;
765 m_arrival_dist.set(Ships[i].arrival_distance);
766 m_arrival_delay.set(Ships[i].arrival_delay);
767 m_departure_delay.set(Ships[i].departure_delay);
769 if (Ships[i].arrival_anchor != m_arrival_target){
770 m_arrival_target = -1;
773 if (!cmp_sexp_chains(a_cue, Ships[i].arrival_cue)) {
775 m_update_arrival = 0;
778 if (!cmp_sexp_chains(d_cue, Ships[i].departure_cue)) {
780 m_update_departure = 0;
783 if ( Ships[i].departure_anchor != m_departure_target ){
784 m_departure_target = -1;
789 // process the first ship in group, else process the rest
790 if (base_ship >= 0) {
791 m_ai_class = Ships[i].weapons.ai_class;
792 cargo = Ships[i].cargo1;
793 m_cargo1 = Cargo_names[cargo];
794 m_hotkey = Ships[i].hotkey + 1;
795 m_score.init(Ships[i].score);
797 m_persona = Ships[i].persona_index + 1;
799 // we use final_death_time member of ship structure for holding the amount of time before a mission
800 // to destroy this ship
801 wing = Ships[i].wingnum;
803 GetDlgItem(IDC_WING) -> SetWindowText("None");
806 GetDlgItem(IDC_WING) -> SetWindowText(Wings[wing].name);
807 if (!query_whole_wing_marked(wing))
808 m_update_arrival = m_update_departure = 0;
811 // set routine local varaiables for ship/object flags
812 no_arrival_warp = (Ships[i].flags & SF_NO_ARRIVAL_WARP) ? 1 : 0;
813 no_departure_warp = (Ships[i].flags & SF_NO_DEPARTURE_WARP) ? 1 : 0;
820 if (Ships[i].weapons.ai_class != m_ai_class){
824 if (Ships[i].cargo1 != cargo){
828 m_score.set(Ships[i].score);
830 if (Ships[i].hotkey != m_hotkey - 1){
834 if ( Ships[i].persona_index != (m_persona-1) ){
838 if (Ships[i].wingnum != wing){
839 GetDlgItem(IDC_WING) -> SetWindowText("");
842 no_arrival_warp = tristate_set(Ships[i].flags & SF_NO_ARRIVAL_WARP, no_arrival_warp);
843 no_departure_warp = tristate_set(Ships[i].flags & SF_NO_DEPARTURE_WARP, no_departure_warp);
849 objp = GET_NEXT(objp);
853 m_arrival_tree.clear_tree("");
854 m_departure_tree.clear_tree("");
858 m_arrival_tree.load_tree(a_cue);
859 m_departure_tree.load_tree(d_cue, "false");
862 m_arrival_tree.clear_tree();
863 m_arrival_tree.DeleteAllItems();
864 m_departure_tree.clear_tree();
865 m_departure_tree.DeleteAllItems();
868 m_player_ship.SetCheck(pship);
869 m_no_arrival_warp.SetCheck(no_arrival_warp);
870 m_no_departure_warp.SetCheck(no_departure_warp);
873 i = m_arrival_tree.select_sexp_node;
875 w = GetDlgItem(IDC_ARRIVAL_TREE);
876 m_arrival_tree.hilite_item(i);
879 i = m_departure_tree.select_sexp_node;
881 w = GetDlgItem(IDC_DEPARTURE_TREE);
882 m_departure_tree.hilite_item(i);
887 } else { // no ships selected, 0 or more player ships selected
888 if (player_count > 1) { // multiple player ships selected
889 Assert(base_player >= 0);
890 m_ship_name = _T("");
891 m_player_ship.SetCheck(TRUE);
892 objp = GET_FIRST(&obj_used_list);
893 while (objp != END_OF_LIST(&obj_used_list)) {
894 if ((objp->type == OBJ_START) && (objp->flags & OF_MARKED)) {
896 if (base_player >= 0) {
897 m_ship_class = Ships[i].ship_info_index;
898 m_team = bitmask_2_bitnum(Ships[i].team);
902 if (Ships[i].ship_info_index != m_ship_class)
904 if (bitmask_2_bitnum(Ships[i].team) != m_team)
909 objp = GET_NEXT(objp);
912 // only 1 player selected..
913 } else if (query_valid_object() && (Objects[cur_object_index].type == OBJ_START)) {
914 Assert((player_count == 1) && !multi_edit);
915 player_ship = Objects[cur_object_index].instance;
916 m_ship_name = Ships[player_ship].ship_name;
917 m_ship_class = Ships[player_ship].ship_info_index;
918 m_team = bitmask_2_bitnum(Ships[player_ship].team);
919 m_player_ship.SetCheck(TRUE);
921 } else { // no ships or players selected..
922 m_ship_name = _T("");
926 m_player_ship.SetCheck(FALSE);
932 m_score.blank(); // cause control to be blank
933 m_arrival_location = -1;
934 m_departure_location = -1;
935 m_arrival_delay.blank();
936 m_departure_delay.blank();
937 m_arrival_dist.blank();
938 m_arrival_target = -1;
939 m_departure_target = -1;
940 m_arrival_tree.clear_tree();
941 m_arrival_tree.DeleteAllItems();
942 m_departure_tree.clear_tree();
943 m_departure_tree.DeleteAllItems();
944 m_no_arrival_warp.SetCheck(0);
945 m_no_departure_warp.SetCheck(0);
946 enable = p_enable = 0;
947 GetDlgItem(IDC_WING)->SetWindowText(_T("None"));
950 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
951 // must put the appropriate ships into the list depending on arrival location
952 if ( m_arrival_location != ARRIVE_FROM_DOCK_BAY ){
953 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
955 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
958 // set the internal variable appropriatly
959 if (m_arrival_target >= SPECIAL_ARRIVAL_ANCHORS_OFFSET){
960 m_arrival_target -= SPECIAL_ARRIVAL_ANCHORS_OFFSET;
961 } else if (m_arrival_target >= 0) {
962 m_arrival_target = box->FindStringExact(-1, Ships[m_arrival_target].ship_name);
965 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
966 // must put the appropriate ships into the list depending on departure location
967 if ( m_departure_location == DEPART_AT_DOCK_BAY ){
968 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
973 if ( m_departure_target >= 0 ){
974 m_departure_target = box->FindStringExact( -1, Ships[m_departure_target].ship_name );
979 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
980 if (!mission_type){ // multiplayer mission
981 box->EnableWindow(TRUE);
985 box->EnableWindow(FALSE);
990 for (i=0; i<2; i++) // hard coded: only allow friendly and hostile
991 box->AddString(Team_names[i]);
993 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
994 box->EnableWindow(enable);
996 for (i=0; i<Num_team_names; i++){
997 box->AddString(Team_names[i]);
1002 m_arrival_dist.display();
1003 m_arrival_delay.display();
1004 m_departure_delay.display();
1010 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(FALSE);
1011 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(FALSE);
1012 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1013 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1014 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(FALSE);
1015 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(FALSE);
1016 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(FALSE);
1017 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1018 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(FALSE);
1019 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(FALSE);
1020 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(FALSE);
1021 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(FALSE);
1022 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(FALSE);
1025 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable);
1026 if (m_arrival_location) {
1027 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable);
1028 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable);
1030 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1031 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1034 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1035 if ( m_departure_location ) {
1036 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
1038 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1041 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(enable);
1042 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(enable);
1043 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
1044 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1045 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable);
1046 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable);
1047 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable);
1048 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable);
1049 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable);
1053 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(!multi_edit);
1054 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(TRUE);
1055 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
1056 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(TRUE);
1057 GetDlgItem(IDC_WEAPONS)->EnableWindow(m_ship_class >= 0);
1058 GetDlgItem(IDC_FLAGS)->EnableWindow(TRUE);
1061 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(FALSE);
1062 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(FALSE);
1063 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
1064 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(FALSE);
1065 GetDlgItem(IDC_WEAPONS)->EnableWindow(FALSE);
1066 GetDlgItem(IDC_FLAGS)->EnableWindow(FALSE);
1069 GetDlgItem(IDC_AI_CLASS)->EnableWindow(enable);
1070 GetDlgItem(IDC_SHIP_CARGO1)->EnableWindow(enable);
1071 GetDlgItem(IDC_HOTKEY)->EnableWindow(enable);
1072 if ((m_ship_class >= 0) && !(Ship_info[m_ship_class].flags & SIF_CARGO) && !(Ship_info[m_ship_class].flags & SIF_NO_SHIP_TYPE))
1073 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1074 else if (multi_edit)
1075 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1077 GetDlgItem(IDC_GOALS)->EnableWindow(FALSE);
1079 // !pship_count used because if allowed to clear, we would have no player starts
1080 if (mission_type || !pship_count || (pship_count + total_count > MAX_PLAYERS) || (pvalid_count < total_count))
1081 m_player_ship.EnableWindow(FALSE);
1083 m_player_ship.EnableWindow(TRUE);
1085 GetDlgItem(IDC_DELETE_SHIP)->EnableWindow(enable);
1086 GetDlgItem(IDC_SHIP_RESET)->EnableWindow(enable);
1087 GetDlgItem(IDC_SCORE)->EnableWindow(enable);
1090 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(m_ship_class >= 0);
1092 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(0);
1093 GetDlgItem(IDC_SHIP_TBL)->ShowWindow(SW_HIDE);
1096 if (cue_init > 1) { // more than one ship (players don't have cues to edit)
1097 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_SHOW);
1098 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_SHOW);
1101 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_HIDE);
1102 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_HIDE);
1105 if (multi_edit || (total_count > 1)) {
1106 // we will allow the ignore orders dialog to be multi edit if all selected
1107 // ships are the same type. the ship_type (local) variable holds the ship types
1108 // for all ships. Determine how may bits set and enable/diable window
1110 if ( /*(m_team == -1) ||*/ (ship_orders == -1) ){
1111 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(FALSE);
1113 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(TRUE);
1116 // always enabled when one ship is selected
1117 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(enable);
1119 // always enabled if >= 1 ship selected
1120 GetDlgItem(IDC_SHIP_PERSONA)->EnableWindow(enable);
1123 SetWindowText("Edit Marked Ships");
1124 } else if (player_count) {
1125 SetWindowText("Edit Player Ship");
1127 SetWindowText("Edit Ship");
1130 // setup alternate name stuff
1131 if(player_ship >= 0){
1132 ship_alt_name_init(player_ship);
1134 ship_alt_name_init(single_ship);
1143 // update ship structure(s) with dialog data. The data is first checked for errors. If
1144 // no errors occur, returns 0. If an error occurs, returns -1. If the update is bypassed,
1145 // returns 1. Bypass is necessary to avoid an infinite loop, and it doesn't actually
1146 // update the data. Bypass only occurs if bypass mode is active and we still get an error.
1147 // Once the error no longer occurs, bypass mode is cleared and data is updated.
1148 int CShipEditorDlg::update_data(int redraw)
1150 char *str, old_name[255];
1153 CSingleLock sync(&CS_cur_object_index), sync2(&CS_update);
1155 nprintf(("Fred routing", "Ship dialog save\n"));
1156 if (!GetSafeHwnd() || !initialized || bypass_all)
1159 sync.Lock(); // don't allow cur_object_index to change while we are using it
1160 sync2.Lock(); // don't allow reinitialization until we are done updating
1163 Wing_editor_dialog.update_data_safe();
1164 if (multi_edit) { // editing multiple ships (ships and/or players)
1165 ptr = GET_FIRST(&obj_used_list);
1166 while (ptr != END_OF_LIST(&obj_used_list)) {
1167 if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags & OF_MARKED))
1168 update_ship(get_ship_from_obj(ptr));
1170 ptr = GET_NEXT(ptr);
1173 } else if (player_ship >= 0) { // editing a single player
1174 update_ship(player_ship);
1176 } else if (single_ship >= 0) { // editing a single ship
1177 ptr = GET_FIRST(&obj_used_list);
1178 while (ptr != END_OF_LIST(&obj_used_list)) {
1179 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (cur_object_index != OBJ_INDEX(ptr))) {
1180 str = Ships[ptr->instance].ship_name;
1181 if (!stricmp(m_ship_name, str)) {
1186 z = MessageBox("This ship name is already being used by another ship\n"
1187 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1192 m_ship_name = _T(Ships[single_ship].ship_name);
1197 ptr = GET_NEXT(ptr);
1200 for (i=0; i<MAX_WINGS; i++)
1201 if (Wings[i].wave_count && !stricmp(Wings[i].name, m_ship_name)) {
1206 z = MessageBox("This ship name is already being used by a wing\n"
1207 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1212 m_ship_name = _T(Ships[single_ship].ship_name);
1216 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
1217 if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_ship_name)) {
1222 z = MessageBox("This ship name is already being used by a waypoint path\n"
1223 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1228 m_ship_name = _T(Ships[single_ship].ship_name);
1232 for (i=0; i<Num_jump_nodes; i++)
1233 if (!stricmp(Jump_nodes[i].name, m_ship_name)) {
1238 z = MessageBox("This ship name is already being used by a jump node\n"
1239 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1244 m_ship_name = _T(Ships[single_ship].ship_name);
1248 wing = Ships[single_ship].wingnum;
1250 Assert((wing < MAX_WINGS) && Wings[wing].wave_count);
1251 for (i=0; i<Wings[wing].wave_count; i++)
1252 if (wing_objects[wing][i] == Ships[single_ship].objnum)
1255 Assert(i < Wings[wing].wave_count);
1256 sprintf(old_name, "%s %d", Wings[wing].name, i + 1);
1257 if (stricmp(old_name, m_ship_name)) {
1261 if (MessageBox("This ship is part of a wing, and it's name cannot be changed",
1262 NULL, MB_OKCANCEL) == IDCANCEL)
1265 m_ship_name = _T(old_name);
1270 z = update_ship(single_ship);
1274 strcpy(old_name, Ships[single_ship].ship_name);
1275 string_copy(Ships[single_ship].ship_name, m_ship_name, NAME_LENGTH, 1);
1276 str = Ships[single_ship].ship_name;
1277 if (stricmp(old_name, str)) {
1278 update_sexp_references(old_name, str);
1279 ai_update_goal_references(REF_TYPE_SHIP, old_name, str);
1280 for (i=0; i<Num_reinforcements; i++)
1281 if (!stricmp(old_name, Reinforcements[i].name)) {
1282 Assert(strlen(str) < NAME_LENGTH);
1283 strcpy(Reinforcements[i].name, str);
1290 if (Player_start_shipnum < 0 || Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) { // need a new single player start.
1291 ptr = GET_FIRST(&obj_used_list);
1292 while (ptr != END_OF_LIST(&obj_used_list)) {
1293 if (ptr->type == OBJ_START) {
1294 Player_start_shipnum = ptr->instance;
1298 ptr = GET_NEXT(ptr);
1305 Wing_editor_dialog.initialize_data_safe(1);
1310 update_map_window();
1315 int CShipEditorDlg::update_ship(int ship)
1322 // THIS DIALOG IS THE SOME OF THE WORST CODE I HAVE EVER SEEN IN MY ENTIRE LIFE.
1323 // IT TOOK A RIDICULOUSLY LONG AMOUNT OF TIME TO ADD 2 FUNCTIONS. OMG
1324 ship_alt_name_close(ship);
1326 if ((Ships[ship].ship_info_index != m_ship_class) && (m_ship_class != -1)) {
1327 change_ship_type(ship, m_ship_class);
1332 MODIFY(Ships[ship].team, 1 << m_team);
1334 if (Objects[Ships[ship].objnum].type != OBJ_SHIP){
1335 if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)){
1340 if (m_ai_class != -1){
1341 MODIFY(Ships[ship].weapons.ai_class, m_ai_class);
1343 if (strlen(m_cargo1)) {
1344 z = string_lookup(m_cargo1, Cargo_names, Num_cargo);
1346 Assert(Num_cargo < MAX_CARGO);
1348 strcpy(Cargo_names[z], m_cargo1);
1351 MODIFY(Ships[ship].cargo1, (char)z);
1354 m_score.save(&Ships[ship].score);
1355 if (m_arrival_location != -1)
1356 MODIFY(Ships[ship].arrival_location, m_arrival_location);
1357 if (m_departure_location != -1)
1358 MODIFY(Ships[ship].departure_location, m_departure_location);
1360 // do the persona update
1361 // m_persona holds the index into the list. Get the item data associated with this index and then
1362 // assign to the ship taking care that we check for the NO_PERSONA_INDEX id
1363 box = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
1364 persona = box->GetItemData(m_persona);
1365 if ( persona == NO_PERSONA_INDEX )
1368 MODIFY(Ships[ship].persona_index, persona);
1370 if (Ships[ship].wingnum < 0) {
1371 if (!multi_edit || m_update_arrival) { // should we update the arrival cue?
1372 if (Ships[ship].arrival_cue >= 0)
1373 free_sexp2(Ships[ship].arrival_cue);
1375 Ships[ship].arrival_cue = m_arrival_tree.save_tree();
1378 if (!multi_edit || m_update_departure) {
1379 if (Ships[ship].departure_cue >= 0)
1380 free_sexp2(Ships[ship].departure_cue);
1382 Ships[ship].departure_cue = m_departure_tree.save_tree();
1385 m_arrival_dist.save(&Ships[ship].arrival_distance);
1386 m_arrival_delay.save(&Ships[ship].arrival_delay);
1387 m_departure_delay.save(&Ships[ship].departure_delay);
1388 if (m_arrival_target >= 0) {
1389 z = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
1390 MODIFY(Ships[ship].arrival_anchor, z);
1392 // if the arrival is not hyperspace or docking bay -- force arrival distance to be
1393 // greater than 2*radius of target.
1394 if (((m_arrival_location != ARRIVE_FROM_DOCK_BAY) && (m_arrival_location != ARRIVE_AT_LOCATION)) && (z >= 0) && (z < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
1395 d = int(min(500, 2.0f * Objects[Ships[ship].objnum].radius));
1396 if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) {
1397 str.Format("Ship must arrive at least %d meters away from target.\n"
1398 "Value has been reset to this. Use with caution!\r\n"
1399 "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[ship].objnum].radius) );
1402 if (Ships[ship].arrival_distance < 0)
1403 Ships[ship].arrival_distance = -d;
1405 Ships[ship].arrival_distance = d;
1407 m_arrival_dist.fix(Ships[ship].arrival_distance);
1411 z = ((CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
1412 MODIFY(Ships[ship].departure_anchor, z );
1416 MODIFY(Ships[ship].hotkey, m_hotkey - 1);
1418 switch( m_no_arrival_warp.GetCheck() ) {
1420 if (Ships[ship].flags & SF_NO_ARRIVAL_WARP)
1423 Ships[ship].flags &= ~SF_NO_ARRIVAL_WARP;
1427 if (!(Ships[ship].flags & SF_NO_ARRIVAL_WARP))
1430 Ships[ship].flags |= SF_NO_ARRIVAL_WARP;
1434 switch( m_no_departure_warp.GetCheck() ) {
1436 if (Ships[ship].flags & SF_NO_DEPARTURE_WARP)
1439 Ships[ship].flags &= ~SF_NO_DEPARTURE_WARP;
1443 if (!(Ships[ship].flags & SF_NO_DEPARTURE_WARP))
1446 Ships[ship].flags |= SF_NO_DEPARTURE_WARP;
1450 switch (m_player_ship.GetCheck()) {
1452 if (Objects[Ships[ship].objnum].type != OBJ_START) {
1457 Objects[Ships[ship].objnum].type = OBJ_START;
1461 if (Objects[Ships[ship].objnum].type == OBJ_START) {
1466 Objects[Ships[ship].objnum].type = OBJ_SHIP;
1474 void CShipEditorDlg::OnOK()
1482 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
1487 void CShipEditorDlg::OnInitMenu(CMenu *pMenu)
1491 m = pMenu->GetSubMenu(0);
1493 generate_ship_popup_menu(m, ID_SHIP_MENU, MF_ENABLED, SHIP_FILTER_PLAYERS);
1495 m->CheckMenuItem(ID_SHIP_MENU + cur_ship, MF_BYCOMMAND | MF_CHECKED);
1497 CWnd::OnInitMenu(pMenu);
1500 BOOL CShipEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam)
1504 id = LOWORD(wParam);
1505 if (id >= ID_SHIP_MENU && id < ID_SHIP_MENU + MAX_SHIPS) {
1506 if (!update_data()) {
1507 ship = id - ID_SHIP_MENU;
1509 set_cur_object_index(Ships[ship].objnum);
1514 return CDialog::OnCommand(wParam, lParam);
1517 void CShipEditorDlg::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1519 m_arrival_tree.right_clicked();
1523 void CShipEditorDlg::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1525 m_departure_tree.right_clicked();
1529 void CShipEditorDlg::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1531 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1533 if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1535 modified = editing = 1;
1541 void CShipEditorDlg::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1543 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1545 if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1547 modified = editing = 1;
1553 void CShipEditorDlg::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1555 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1557 *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1561 void CShipEditorDlg::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1563 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1565 *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1569 int CShipEditorDlg::verify()
1571 nprintf(("Fred routing", "Ship dialog verify\n"));
1572 if (!GetSafeHwnd() || !modified)
1581 void CShipEditorDlg::OnGoals()
1583 ShipGoalsDlg dlg_goals;
1585 Assert(query_valid_object());
1587 // dlg_goals.initialize_multi();
1590 // Assert(single_ship != -1);
1591 // dlg_goals.self_ship = single_ship;
1592 // dlg_goals.initialize(Ai_info[Ships[single_ship].ai_index].goals);
1596 Assert(single_ship != -1);
1597 dlg_goals.self_ship = single_ship;
1600 dlg_goals.DoModal();
1601 if (!multi_edit && !query_initial_orders_empty(Ai_info[Ships[single_ship].ai_index].goals))
1602 if ((Ships[single_ship].wingnum >= 0) && (query_initial_orders_conflict(Ships[single_ship].wingnum)))
1603 MessageBox("This ship's wing also has initial orders", "Possible conflict");
1606 void CShipEditorDlg::OnSelchangeShipClass()
1612 ptr = GET_FIRST(&obj_used_list);
1613 while (ptr != END_OF_LIST(&obj_used_list)) {
1614 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags & OF_MARKED))
1615 if (Ships[ptr->instance].ship_info_index != m_ship_class) {
1616 change_ship_type(ptr->instance, m_ship_class);
1620 ptr = GET_NEXT(ptr);
1623 update_map_window();
1626 void CShipEditorDlg::OnInitialStatus()
1630 dlg.m_multi_edit = multi_edit;
1634 void CShipEditorDlg::OnWeapons()
1637 WeaponEditorDlg dlg;
1641 dlg.m_multi_edit = multi_edit;
1645 objp = GET_FIRST(&obj_used_list);
1646 while (objp != END_OF_LIST(&obj_used_list)) {
1647 if (objp->flags & OF_MARKED)
1648 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
1651 if (Ships[i].weapons.ai_class != Ships[ship].weapons.ai_class)
1656 m_ai_class = Ships[i].weapons.ai_class;
1660 objp = GET_NEXT(objp);
1669 m_ai_class = Ships[ship].weapons.ai_class;
1672 box = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
1673 box->SetCurSel(m_ai_class);
1676 void CShipEditorDlg::OnShipReset()
1678 int i, j, index, ship;
1683 model_subsystem *sp;
1685 m_cargo1 = "Nothing";
1686 m_ai_class = AI_DEFAULT_CLASS;
1688 if (Ship_info[m_ship_class].species == SPECIES_SHIVAN)
1689 m_team = TEAM_HOSTILE;
1691 m_team = TEAM_FRIENDLY;
1694 objp = GET_FIRST(&obj_used_list);
1695 while (objp != END_OF_LIST(&obj_used_list)) {
1696 if (((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) && (objp->flags & OF_MARKED)) {
1697 ship = objp->instance;
1700 for (i=0; i<MAX_AI_GOALS; i++){
1701 Ai_info[Ships[ship].ai_index].goals[i].ai_mode = AI_GOAL_NONE;
1704 objp->phys_info.speed = 0.0f;
1705 objp->shields[0] = 100.0f;
1706 objp->hull_strength = 100.0f;
1708 sip = &Ship_info[Ships[ship].ship_info_index];
1709 for (i=0; i<sip->num_primary_banks; i++)
1710 Ships[ship].weapons.primary_bank_weapons[i] = sip->primary_bank_weapons[i];
1712 for (i=0; i<sip->num_secondary_banks; i++) {
1713 Ships[ship].weapons.secondary_bank_weapons[i] = sip->secondary_bank_weapons[i];
1714 Ships[ship].weapons.secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i];
1718 ptr = GET_FIRST(&Ships[ship].subsys_list);
1719 while (ptr != END_OF_LIST(&Ships[ship].subsys_list)) {
1720 ptr->current_hits = 0.0f;
1721 if (ptr->system_info->type == SUBSYSTEM_TURRET) {
1723 sp = &Ship_info[Ships[ship].ship_info_index].subsystems[index];
1726 for (i=0; i<MAX_PRIMARY_BANKS; i++){
1727 if (sp->primary_banks[i] != -1){
1728 wp->primary_bank_weapons[j++] = sp->primary_banks[i];
1732 wp->num_primary_banks = j;
1734 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1735 if (sp->secondary_banks[i] != -1) {
1736 wp->secondary_bank_weapons[j] = sp->secondary_banks[i];
1737 wp->secondary_bank_capacity[j++] = sp->secondary_bank_capacity[i];
1741 wp->num_secondary_banks = j;
1742 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1743 wp->secondary_bank_ammo[i] = 100;
1748 ptr = GET_NEXT(ptr);
1752 objp = GET_NEXT(objp);
1757 MessageBox("Ships reset to ship class defaults");
1759 MessageBox("Ship reset to ship class defaults");
1763 void CShipEditorDlg::OnDeleteShip()
1769 void CShipEditorDlg::OnShipTbl()
1773 dlg.set(m_ship_class);
1777 int CShipEditorDlg::make_ship_list(int *arr)
1782 ptr = GET_FIRST(&obj_used_list);
1783 while (ptr != END_OF_LIST(&obj_used_list)) {
1784 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)){
1785 arr[n++] = OBJ_INDEX(ptr);
1788 ptr = GET_NEXT(ptr);
1794 void CShipEditorDlg::OnPrev()
1796 int i, n, arr[MAX_SHIPS];
1798 if (!update_data()) {
1799 n = make_ship_list(arr);
1809 for (i=0; i<n; i++){
1810 if (Ships[cur_ship].objnum == arr[i]){
1823 set_cur_object_index(arr[i]);
1824 Ship_editor_dialog.initialize_data(1);
1831 void CShipEditorDlg::OnNext()
1833 int i, n, arr[MAX_SHIPS];
1835 if (!update_data()) {
1836 n = make_ship_list(arr);
1845 if (Ships[cur_ship].objnum == arr[i])
1855 set_cur_object_index(arr[i]);
1856 Ship_editor_dialog.initialize_data(1);
1863 void CShipEditorDlg::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1867 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1868 h = pNMTreeView->itemNew.hItem;
1870 m_arrival_tree.update_help(h);
1876 void CShipEditorDlg::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1880 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1881 h = pNMTreeView->itemNew.hItem;
1883 m_departure_tree.update_help(h);
1889 void CShipEditorDlg::calc_cue_height()
1893 GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1894 cue_height = cue.bottom - cue.top + 10;
1895 if (Show_sexp_help){
1896 cue_height += SEXP_HELP_BOX_SIZE;
1899 if (Hide_ship_cues) {
1900 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1905 void CShipEditorDlg::show_hide_sexp_help()
1909 if (Show_sexp_help){
1910 cue_height += SEXP_HELP_BOX_SIZE;
1912 cue_height -= SEXP_HELP_BOX_SIZE;
1915 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()){
1919 GetWindowRect(rect);
1921 if (Show_sexp_help){
1922 rect.bottom += SEXP_HELP_BOX_SIZE;
1924 rect.bottom -= SEXP_HELP_BOX_SIZE;
1930 void CShipEditorDlg::OnHideCues()
1934 GetWindowRect(rect);
1935 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1936 rect.bottom -= cue_height;
1940 rect.bottom += cue_height;
1947 void CShipEditorDlg::OnSelchangeArrivalLocation()
1952 box = (CComboBox *)GetDlgItem( IDC_ARRIVAL_TARGET );
1953 if (m_arrival_location) {
1954 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE);
1955 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE);
1956 if (m_arrival_target < 0) {
1957 m_arrival_target = 0;
1960 // determine which items we should put into the arrival target combo box
1961 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
1962 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1964 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1968 m_arrival_target = -1;
1969 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1970 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1975 void CShipEditorDlg::OnSelchangeDepartureLocation()
1980 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1981 if ( m_departure_location ) {
1982 box->EnableWindow(TRUE);
1983 if ( m_departure_target < 0 ) {
1984 m_departure_target = 0;
1987 // we need to build up the list box content based on the departure type. When
1988 // from a docking bay, only show ships in the list which have them. Show all ships otherwise
1989 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
1990 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1992 // I think that this section is currently illegal
1997 m_departure_target = -1;
1998 box->EnableWindow(FALSE);
2004 void CShipEditorDlg::OnPlayerShip()
2006 if (m_player_ship.GetCheck() == 1)
2007 m_player_ship.SetCheck(0);
2009 m_player_ship.SetCheck(1);
2011 update_map_window();
2014 void CShipEditorDlg::OnNoArrivalWarp()
2016 if (m_no_arrival_warp.GetCheck() == 1)
2017 m_no_arrival_warp.SetCheck(0);
2019 m_no_arrival_warp.SetCheck(1);
2022 void CShipEditorDlg::OnNoDepartureWarp()
2024 if (m_no_departure_warp.GetCheck() == 1)
2025 m_no_departure_warp.SetCheck(0);
2027 m_no_departure_warp.SetCheck(1);
2031 // function to possibly warn user when he selects a hotkey which might be used for
2033 void CShipEditorDlg::OnSelchangeHotkey()
2039 set_num = m_hotkey-1; // use -1 since values associated with hotkey sets are 1 index based
2041 // the first three sets are generally reserved for player starting wings.
2042 if ( set_num < MAX_STARTING_WINGS ) {
2043 sprintf( buf, "This hotkey set should probably be reserved\nfor wing %s", Starting_wing_names[set_num] );
2044 MessageBox(buf, NULL, MB_OK);
2048 void CShipEditorDlg::OnFlags()
2052 dlg.setup(p_enable);
2056 void CShipEditorDlg::OnIgnoreOrders()
2058 // TODO: Add your control notification handler code here
2059 ignore_orders_dlg player_order_dlg;
2061 Assert(query_valid_object());
2064 if ( single_ship != -1 ){
2065 player_order_dlg.m_ship = single_ship;
2067 player_order_dlg.m_ship = player_ship;
2070 player_order_dlg.m_ship = -1;
2073 player_order_dlg.DoModal();
2076 void CShipEditorDlg::OnSpecialExp()
2078 // TODO: Add your control notification handler code here
2079 ShipSpecialDamage dlg;
2083 // alternate ship name stuff
2084 void CShipEditorDlg::ship_alt_name_init(int base_ship)
2087 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2095 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
2098 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
2100 // reset the combobox and add all relevant strings
2101 ptr->ResetContent();
2102 ptr->AddString("<none>");
2103 for(idx=0; idx<Mission_alt_type_count; idx++){
2104 ptr->AddString(Mission_alt_types[idx]);
2112 // otherwise look his stuff up
2113 if(strlen(Fred_alt_names[base_ship])){
2114 ptr->SelectString(0, Fred_alt_names[base_ship]);
2120 void CShipEditorDlg::ship_alt_name_close(int base_ship)
2123 char str[NAME_LENGTH+2] = "";
2125 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2136 // see if we have something besides "none" selected
2137 ptr->GetWindowText(cstr);
2138 if(cstr == CString("<none>")){
2140 strcpy(Fred_alt_names[base_ship], "");
2144 p = cstr.GetBuffer(0);
2150 // otherwise see if it already exists
2151 if(mission_parse_lookup_alt(str) >= 0){
2152 strcpy(Fred_alt_names[base_ship], str);
2157 // otherwise try and add it
2158 if(mission_parse_add_alt(str) >= 0){
2159 strcpy(Fred_alt_names[base_ship], str);
2164 // bad - couldn't add
2165 strcpy(Fred_alt_names[base_ship], "");
2166 MessageBox("Couldn't add new alternate type name. Already using too many!");