2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/fred2/ShipEditorDlg.cpp $
15 * Single ship editing dialog
18 * Revision 1.3 2002/06/09 04:41:17 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:44 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:08 root
28 * 8 8/18/99 1:32p Andsager
29 * Mark Vasudan wingmen as such.
31 * 7 8/18/99 1:12p Andsager
32 * Allow ships to be assigned Vasudan persona (wingman 6)
34 * 6 8/16/99 10:52p Andsager
35 * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
37 * 5 8/11/99 9:27a Andsager
38 * Fix compile warning.
40 * 4 5/20/99 6:59p Dave
41 * Added alternate type names for ships. Changed swarm missile table
44 * 3 2/11/99 2:15p Andsager
45 * Add ship explosion modification to FRED
47 * 2 10/07/98 6:28p Dave
48 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
49 * Fred. Globalized mission and campaign file extensions. Removed Silent
50 * Threat specific code.
52 * 1 10/07/98 3:02p Dave
54 * 1 10/07/98 3:00p Dave
56 * 157 6/16/98 10:17a Hoffoss
57 * Fixed define that was backwards and no one caught before release (ya,
60 * 156 5/23/98 3:33p Hoffoss
61 * Removed unused code in reinforcements editor and make ships.tbl button
62 * in ship editor disappear in release build.
64 * 155 5/21/98 12:58a Hoffoss
65 * Fixed warnings optimized build turned up.
67 * 154 4/28/98 2:13p Hoffoss
68 * Added code to help keep invalid player ship types from existing in
71 * 153 4/24/98 2:57p Jim
74 * 152 4/22/98 11:55a Hoffoss
75 * Fixed bug with ship editor's hide cue button when sexp help is on at
78 * 151 4/16/98 5:59p Duncan
79 * Fixed bad assumption, apparently.
81 * 150 4/07/98 9:42a Allender
82 * put in persona combo box into ship editor. Removed code to assign
83 * personas based on message
85 * 149 3/30/98 1:15p Hoffoss
86 * Fixed bug with arrival/departure cue window size calculation. Wasn't
87 * working anymore after my changes to dialog initing at startup.
89 * 148 3/27/98 12:02p Sandeep
91 * 147 3/25/98 4:14p Hoffoss
92 * Split ship editor up into ship editor and a misc dialog, which tracks
95 * 146 3/21/98 7:36p Lawrance
96 * Move jump nodes to own lib.
98 * 145 3/16/98 8:27p Allender
99 * Fred support for two new AI flags -- kamikaze and no dynamic goals.
101 * 144 3/10/98 6:11p Hoffoss
102 * Added jump node renaming abilities to Fred.
104 * 143 3/09/98 4:30p Allender
105 * multiplayer secondary weapon changes. red-alert and cargo-known-delay
106 * sexpressions. Add time cargo revealed to ship structure
108 * 142 2/22/98 1:21a Hoffoss
109 * Disabled weapon editor if mutliple ship types marked.
111 * 141 2/17/98 12:07p Hoffoss
112 * Changed over to using SF_CARGO_REVEALED in fred.
114 * 140 2/17/98 11:42a Hoffoss
115 * Added support for hidden from sensors condition.
117 * 139 2/13/98 2:42p Duncan
118 * Fixed bug, moved line down where it needs to be because
119 * pre-initializations need to be done first.
121 * 138 2/10/98 1:42p Allender
122 * allow > MAX_ESCORT_SHIPS to be marked as escort ships
124 * 137 2/06/98 2:54p Hoffoss
125 * Fixed some bugs in dialog init, and cleared up some of the confusion
126 * about how it works by renaming some variables and adding comments.
128 * 136 2/06/98 10:48a Hoffoss
129 * Fixed bug with not being able to make ships players in multi mode
132 * 135 2/04/98 4:32p Allender
133 * support for multiple briefings and debriefings. Changes to mission
134 * type (now a bitfield). Bitfield defs for multiplayer modes
136 * 134 1/29/98 5:14p Hoffoss
137 * Added support for a SF_INVULNERABLE ship flag in Fred.
139 * 133 1/12/98 10:41a Allender
140 * fixed minor bug with ship editor and ignore orders dialog
142 * 132 12/05/97 4:07p Hoffoss
143 * Changed code to allow WHO_FROM type ship sources to only show flyable
146 * 131 11/24/97 2:31p Allender
147 * allow ignore orders dialog to be active for players
149 * 130 11/24/97 9:07a Allender
150 * ignore orders dialog should function as multi-edit now
152 * 129 11/22/97 4:17p Allender
153 * first pass of making ignore orders dialog multi edit
155 * 128 11/13/97 4:14p Allender
156 * automatic assignment of hotkeys for starting wings. Appripriate
157 * warnings when they are incorrectly used. hotkeys correctly assigned to
158 * ships/wing arriving after mission start
160 * 127 11/11/97 3:32p Johnson
161 * allender: Combo boxes need to have lists initialized before setting
162 * internal class variable for arrival/depature targets
164 * 126 11/11/97 2:13p Allender
165 * docking bay support for Fred and Freespace. Added hook to ai code for
166 * arrival/departure from dock bays. Fred support now sufficient.
168 * 125 11/10/97 10:13p Allender
169 * added departure anchor to Fred and Freespace in preparation for using
170 * docking bays. Functional in Fred, not in FreeSpace.
172 * 124 10/21/97 4:49p Allender
173 * added flags to Fred and FreeSpace to forgo warp effect (toggle in ship
176 * 123 10/14/97 5:33p Hoffoss
177 * Added Fred support (and fsm support) for the no_arrival_music flags in
180 * 122 9/18/97 10:49a Allender
181 * increment/decrement Player_start variable when making a ship a player
184 * 121 9/17/97 5:43p Hoffoss
185 * Added Fred support for new player start information.
187 * 120 9/16/97 9:41p Hoffoss
188 * Changed Fred code around to stop using Parse_player structure for
189 * player information, and use actual ships instead.
191 * 119 9/15/97 2:35p Hoffoss
192 * Fixed bug in Fred where a player ship and normal ship both marked
193 * clobbered each other's ship type in ship editor dialog.
195 * 118 9/09/97 10:29a Hoffoss
196 * Added support for neutral team, and fixed changes made to how team is
197 * used in ship structure.
199 * 117 9/09/97 9:27a Hoffoss
200 * Removed #Jason Hoffoss# comments from code. Code is already set up to
201 * handle the situation properly.
203 * 116 9/06/97 2:13p Mike
204 * Replace support for TEAM_NEUTRAL
206 * 115 9/04/97 5:35p Hoffoss
207 * Fixed arrival distance stuff.
209 * 114 9/04/97 5:04p Johnson
210 * Fixed bug with arrival target distance checking.
212 * 113 9/04/97 4:31p Hoffoss
213 * Fixed bug: Changed ship editor to not touch wing info (arrival or
214 * departure cues) to avoid conflicts with wing editor's changes.
216 * 112 8/30/97 9:52p Hoffoss
217 * Implemented arrival location, distance, and anchor in Fred.
219 * 111 8/28/97 8:56a Hoffoss
220 * Added more checking to sexp error checker, fixed some bugs.
222 * 110 8/25/97 5:56p Hoffoss
223 * Added multiple asteroid field support, loading and saving of asteroid
224 * fields, and ship score field to Fred.
226 * 109 8/22/97 4:16p Hoffoss
227 * added support for arrival and departure info in ship editor using
228 * wing's info if editing marked ships in a wing instead of using ship's.
230 * 108 8/21/97 11:37p Hoffoss
231 * Fixed bug: when renaming a ship that is a reinforcement, an extra
232 * instance of it is added to the reinforcement list.
234 * 107 8/20/97 6:53p Hoffoss
235 * Implemented escort flag support in Fred.
237 * 106 8/19/97 2:53p Hoffoss
238 * Fixed bug where multiple ships editing doesn't change players.
240 * 105 8/19/97 1:44p Hoffoss
241 * Fixed bug with updating too quickly (i.e. via prev and next buttons).
249 #include "fredview.h"
257 #include "management.h"
258 #include "linklist.h"
259 #include "initialstatus.h"
260 #include "weaponeditordlg.h"
262 #include "textviewdlg.h"
263 #include "player.h" // used for the max_keyed_target stuff
264 #include "ignoreordersdlg.h"
265 #include "missionparse.h"
267 #include "starfield.h"
268 #include "jumpnode.h"
269 #include "shipflagsdlg.h"
270 #include "missionmessage.h"
271 #include "shipspecialdamage.h"
273 #define ID_SHIP_MENU 9000
275 #define NO_PERSONA_INDEX 999
278 #define new DEBUG_NEW
280 static char THIS_FILE[] = __FILE__;
283 void numeric_edit_control::setup(int id, CWnd *wnd)
289 void numeric_edit_control::init(int n)
295 void numeric_edit_control::set(int n)
302 void numeric_edit_control::display()
307 str.Format("%d", value);
310 dlg->GetDlgItem(control_id)->SetWindowText(str);
313 void numeric_edit_control::save(int *n)
318 dlg->GetDlgItem(control_id)->GetWindowText(str);
320 MODIFY(*n, atoi(str));
325 void numeric_edit_control::fix(int n)
333 w = dlg->GetDlgItem(control_id);
334 dlg->GetDlgItem(control_id)->SetWindowText(str);
338 /////////////////////////////////////////////////////////////////////////////
339 // CShipEditorDlg dialog
341 CShipEditorDlg::CShipEditorDlg(CWnd* pParent /*=NULL*/)
342 : CDialog(CShipEditorDlg::IDD, pParent)
344 //{{AFX_DATA_INIT(CShipEditorDlg)
345 m_ship_name = _T("");
349 m_arrival_location = -1;
350 m_departure_location = -1;
353 m_update_arrival = FALSE;
354 m_update_departure = FALSE;
355 m_arrival_target = -1;
356 m_departure_target = -1;
361 initialized = editing = multi_edit = 0;
362 select_sexp_node = -1;
366 // Modeless constructor, MK
367 CShipEditorDlg::CShipEditorDlg(CView* pView)
370 initialized = editing = 0;
371 select_sexp_node = -1;
374 void CShipEditorDlg::DoDataExchange(CDataExchange* pDX)
379 CDialog::DoDataExchange(pDX);
380 //{{AFX_DATA_MAP(CShipEditorDlg)
381 DDX_Control(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp);
382 DDX_Control(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp);
383 DDX_Control(pDX, IDC_PLAYER_SHIP, m_player_ship);
384 DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin);
385 DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin);
386 DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree);
387 DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree);
388 DDX_Text(pDX, IDC_SHIP_NAME, m_ship_name);
389 DDX_CBString(pDX, IDC_SHIP_CARGO1, m_cargo1);
390 DDX_CBIndex(pDX, IDC_SHIP_CLASS, m_ship_class);
391 DDX_CBIndex(pDX, IDC_SHIP_TEAM, m_team);
392 DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location);
393 DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location);
394 DDX_CBIndex(pDX, IDC_AI_CLASS, m_ai_class);
395 DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey);
396 DDX_Check(pDX, IDC_UPDATE_ARRIVAL, m_update_arrival);
397 DDX_Check(pDX, IDC_UPDATE_DEPARTURE, m_update_departure);
398 DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target);
399 DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target);
400 DDX_CBIndex(pDX, IDC_SHIP_PERSONA, m_persona);
402 DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1);
403 DDV_MaxChars(pDX, m_cargo1, NAME_LENGTH - 1);
405 if (pDX->m_bSaveAndValidate) { // get dialog control values
406 GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str);
412 m_arrival_delay.init(n);
414 GetDlgItem(IDC_ARRIVAL_DISTANCE)->GetWindowText(str);
415 m_arrival_dist.init(atoi(str));
417 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
421 m_departure_delay.init(n);
423 GetDlgItem(IDC_SCORE)->GetWindowText(str);
424 m_score.init(atoi(str));
428 BEGIN_MESSAGE_MAP(CShipEditorDlg, CDialog)
429 //{{AFX_MSG_MAP(CShipEditorDlg)
431 ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree)
432 ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree)
433 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree)
434 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree)
435 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree)
436 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree)
437 ON_BN_CLICKED(IDC_GOALS, OnGoals)
438 ON_CBN_SELCHANGE(IDC_SHIP_CLASS, OnSelchangeShipClass)
439 ON_BN_CLICKED(IDC_INITIAL_STATUS, OnInitialStatus)
440 ON_BN_CLICKED(IDC_WEAPONS, OnWeapons)
441 ON_BN_CLICKED(IDC_SHIP_RESET, OnShipReset)
442 ON_BN_CLICKED(IDC_DELETE_SHIP, OnDeleteShip)
443 ON_BN_CLICKED(IDC_SHIP_TBL, OnShipTbl)
444 ON_BN_CLICKED(IDC_NEXT, OnNext)
445 ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree)
446 ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree)
447 ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues)
448 ON_BN_CLICKED(IDC_PREV, OnPrev)
449 ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation)
450 ON_BN_CLICKED(IDC_PLAYER_SHIP, OnPlayerShip)
451 ON_BN_CLICKED(IDC_NO_ARRIVAL_WARP, OnNoArrivalWarp)
452 ON_BN_CLICKED(IDC_NO_DEPARTURE_WARP, OnNoDepartureWarp)
453 ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation)
454 ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey)
455 ON_BN_CLICKED(IDC_FLAGS, OnFlags)
456 ON_BN_CLICKED(IDC_IGNORE_ORDERS, OnIgnoreOrders)
458 ON_BN_CLICKED(IDC_SPECIAL_EXP, OnSpecialExp)
462 /////////////////////////////////////////////////////////////////////////////
463 // CShipEditorDlg message handlers
465 BOOL CShipEditorDlg::Create()
471 r = CDialog::Create(IDD, Fred_main_wnd);
473 ptr = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
475 for (i=0; i<MAX_ARRIVAL_NAMES; i++){
476 ptr->AddString(Arrival_location_names[i]);
479 ptr = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
481 for (i=0; i<MAX_DEPARTURE_NAMES; i++){
482 ptr->AddString(Departure_location_names[i]);
485 ptr = (CComboBox *) GetDlgItem(IDC_SHIP_CLASS);
487 for (i=0; i<Num_ship_types; i++){
488 ptr->AddString(Ship_info[i].name);
491 ptr = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
493 for (i=0; i<Num_ai_classes; i++){
494 ptr->AddString(Ai_class_names[i]);
497 // alternate ship name combobox
498 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_ALT);
500 ptr->AddString("<none>");
503 // deal with the persona dialog
504 ptr = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
506 index = ptr->AddString("<None>");
508 ptr->SetItemData(index, NO_PERSONA_INDEX);
511 for ( i = 0; i < Num_personas; i++ ) {
512 if ( Personas[i].flags & PERSONA_FLAG_WINGMAN ) {
515 // don't bother putting any vasudan personas on the list -- done automatically by code
516 // if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
520 CString persona_name = Personas[i].name;
521 if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){
522 persona_name += " -Vas";
525 index = ptr->AddString(persona_name);
527 ptr->SetItemData(index, i);
532 m_score.setup(IDC_SCORE, this);
533 m_arrival_dist.setup(IDC_ARRIVAL_DISTANCE, this);
534 m_arrival_delay.setup(IDC_ARRIVAL_DELAY, this);
535 m_departure_delay.setup(IDC_DEPARTURE_DELAY, this);
538 m_arrival_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog
539 m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
540 m_departure_tree.link_modified(&modified);
541 m_departure_tree.setup();
542 m_arrival_delay_spin.SetRange(0, 999);
543 m_departure_delay_spin.SetRange(0, 999);
549 // This gets called when you click on the "X" button. Note that OnClose
550 // does not destroy the window. It only hides it.
551 void CShipEditorDlg::OnClose()
553 if (verify() && (!bypass_errors)) {
554 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
560 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
565 SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
566 Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
569 BOOL CShipEditorDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
573 r = CDialog::Create(IDD, pParentWnd);
577 int CShipEditorDlg::tristate_set(int val, int cur_state)
593 // called to initialize the dialog box to reflect what ships we currently have marked. Any
594 // time what we have marked changes, this should get called again.
596 // Notes: player_count is the number of player starts marked, when we are in a non-multiplayer
597 // mission (NMM). In a multiplayer mission (MM), player_count will always be zero.
598 // ship_count in NMM is the number of ships (i.e. not player starts) that are marked. In MM,
599 // ship_count is the number of ships and player starts. Total_count is the sum of ship_count
600 // and player_count in all cases. The reason player_count isn't used in MM, and ship_count
601 // is used instead to track player starts is because in MM, player starts can be edited as
602 // freely as AI ships, and are very likely to be AI ships sometimes. Thus, treating them like
603 // AI ships instead of player starts simplifies processing.
605 void CShipEditorDlg::initialize_data(int full_update)
607 int i, type, ship_count, player_count, total_count, wing = -1, pvalid_count;
608 int a_cue, d_cue, cue_init = 0, cargo = 0, base_ship, base_player, pship = -1;
609 int no_arrival_warp = 0, no_departure_warp = 0, escort_count, ship_orders, current_orders;
610 int pship_count; // a total count of the player ships not marked
614 CComboBox *box, *departure_box;
615 CSingleLock sync(&CS_update);
617 nprintf(("Fred routing", "Ship dialog load\n"));
618 if (!GetSafeHwnd() || bypass_all)
621 sync.Lock(); // don't initialize if we are still updating. Wait until update is done.
623 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
624 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
626 departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
627 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
629 if (The_mission.game_type & MISSION_TYPE_MULTI){
630 mission_type = 0; // multi player mission
632 mission_type = 1; // non-multiplayer mission (implies single player mission I guess)
635 // figure out what all we are editing.
636 ship_count = player_count = escort_count = pship_count = pvalid_count = 0;
637 base_ship = base_player = -1;
638 enable = p_enable = 1;
639 objp = GET_FIRST(&obj_used_list);
640 while (objp != END_OF_LIST(&obj_used_list)) {
641 if ((objp->type == OBJ_SHIP) && (Ships[objp->instance].flags & SF_ESCORT)){
642 escort_count++; // get a total count of escort ships
645 if (objp->type == OBJ_START){
646 pship_count++; // count all player starts in mission
649 if (objp->flags & OF_MARKED) {
651 if ((type == OBJ_START) && !mission_type){ // in multiplayer missions, starts act like ships
656 if (type == OBJ_START) {
658 // if player_count is 1, base_player will be the one and only player
659 i = base_player = objp->instance;
661 } else if (type == OBJ_SHIP) {
663 // if ship_count is 1, base_ship will be the one and only ship
664 i = base_ship = objp->instance;
668 if (Ship_info[Ships[i].ship_info_index].flags & SIF_PLAYER_SHIP){
674 objp = GET_NEXT(objp);
677 total_count = ship_count + player_count; // get total number of objects being edited.
678 if (total_count > 1){
685 m_arrival_location = -1;
686 m_arrival_dist.blank();
687 m_arrival_target = -1;
688 m_arrival_delay.blank();
689 m_departure_location = -1;
690 m_departure_target = -1;
691 m_departure_delay.blank();
693 player_ship = single_ship = -1;
694 m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
695 select_sexp_node = -1;
696 ship_orders = 0; // assume they are all the same type
698 box = (CComboBox *) GetDlgItem(IDC_SHIP_CARGO1);
700 for (i=0; i<Num_cargo; i++){
701 box->AddString(Cargo_names[i]);
705 SDL_assert((ship_count == 1) && (base_ship >= 0));
706 m_ship_name = Ships[base_ship].ship_name;
708 m_ship_name = _T("");
711 m_update_arrival = m_update_departure = 1;
713 objp = GET_FIRST(&obj_used_list);
714 while (objp != END_OF_LIST(&obj_used_list)) {
715 if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) {
716 if (objp->flags & OF_MARKED) {
717 // do processing for both ships and players
718 i = get_ship_from_obj(objp);
719 if (base_player >= 0) {
720 m_ship_class = Ships[i].ship_info_index;
721 m_team = bitmask_2_bitnum(Ships[i].team);
722 pship = (objp->type == OBJ_START) ? 1 : 0;
726 if (Ships[i].ship_info_index != m_ship_class)
728 if (bitmask_2_bitnum(Ships[i].team) != m_team)
731 pship = tristate_set(Objects[Ships[i].objnum].type == OBJ_START, pship);
734 // 'and' in the ship type of this ship to our running bitfield
735 current_orders = ship_get_default_orders_accepted( &Ship_info[Ships[i].ship_info_index] );
737 ship_orders = current_orders;
738 } else if (ship_orders != current_orders){
742 if (Ships[i].flags & SF_ESCORT){
743 escort_count--; // remove marked escorts from count
746 if (Objects[Ships[i].objnum].type == OBJ_START){
747 pship_count--; // removed marked starts from count
750 // do processing only for ships (plus players if in a multiplayer mission
751 if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) {
752 // process this if ship not in a wing
753 if (Ships[i].wingnum < 0) {
756 a_cue = Ships[i].arrival_cue;
757 d_cue = Ships[i].departure_cue;
758 m_arrival_location = Ships[i].arrival_location;
759 m_arrival_dist.init(Ships[i].arrival_distance);
760 m_arrival_target = Ships[i].arrival_anchor;
761 m_arrival_delay.init(Ships[i].arrival_delay);
762 m_departure_location = Ships[i].departure_location;
763 m_departure_delay.init(Ships[i].departure_delay);
764 m_departure_target = Ships[i].departure_anchor;
768 if (Ships[i].arrival_location != m_arrival_location){
769 m_arrival_location = -1;
772 if (Ships[i].departure_location != m_departure_location){
773 m_departure_location = -1;
776 m_arrival_dist.set(Ships[i].arrival_distance);
777 m_arrival_delay.set(Ships[i].arrival_delay);
778 m_departure_delay.set(Ships[i].departure_delay);
780 if (Ships[i].arrival_anchor != m_arrival_target){
781 m_arrival_target = -1;
784 if (!cmp_sexp_chains(a_cue, Ships[i].arrival_cue)) {
786 m_update_arrival = 0;
789 if (!cmp_sexp_chains(d_cue, Ships[i].departure_cue)) {
791 m_update_departure = 0;
794 if ( Ships[i].departure_anchor != m_departure_target ){
795 m_departure_target = -1;
800 // process the first ship in group, else process the rest
801 if (base_ship >= 0) {
802 m_ai_class = Ships[i].weapons.ai_class;
803 cargo = Ships[i].cargo1;
804 m_cargo1 = Cargo_names[cargo];
805 m_hotkey = Ships[i].hotkey + 1;
806 m_score.init(Ships[i].score);
808 m_persona = Ships[i].persona_index + 1;
810 // we use final_death_time member of ship structure for holding the amount of time before a mission
811 // to destroy this ship
812 wing = Ships[i].wingnum;
814 GetDlgItem(IDC_WING) -> SetWindowText("None");
817 GetDlgItem(IDC_WING) -> SetWindowText(Wings[wing].name);
818 if (!query_whole_wing_marked(wing))
819 m_update_arrival = m_update_departure = 0;
822 // set routine local varaiables for ship/object flags
823 no_arrival_warp = (Ships[i].flags & SF_NO_ARRIVAL_WARP) ? 1 : 0;
824 no_departure_warp = (Ships[i].flags & SF_NO_DEPARTURE_WARP) ? 1 : 0;
831 if (Ships[i].weapons.ai_class != m_ai_class){
835 if (Ships[i].cargo1 != cargo){
839 m_score.set(Ships[i].score);
841 if (Ships[i].hotkey != m_hotkey - 1){
845 if ( Ships[i].persona_index != (m_persona-1) ){
849 if (Ships[i].wingnum != wing){
850 GetDlgItem(IDC_WING) -> SetWindowText("");
853 no_arrival_warp = tristate_set(Ships[i].flags & SF_NO_ARRIVAL_WARP, no_arrival_warp);
854 no_departure_warp = tristate_set(Ships[i].flags & SF_NO_DEPARTURE_WARP, no_departure_warp);
860 objp = GET_NEXT(objp);
864 m_arrival_tree.clear_tree("");
865 m_departure_tree.clear_tree("");
869 m_arrival_tree.load_tree(a_cue);
870 m_departure_tree.load_tree(d_cue, "false");
873 m_arrival_tree.clear_tree();
874 m_arrival_tree.DeleteAllItems();
875 m_departure_tree.clear_tree();
876 m_departure_tree.DeleteAllItems();
879 m_player_ship.SetCheck(pship);
880 m_no_arrival_warp.SetCheck(no_arrival_warp);
881 m_no_departure_warp.SetCheck(no_departure_warp);
884 i = m_arrival_tree.select_sexp_node;
886 w = GetDlgItem(IDC_ARRIVAL_TREE);
887 m_arrival_tree.hilite_item(i);
890 i = m_departure_tree.select_sexp_node;
892 w = GetDlgItem(IDC_DEPARTURE_TREE);
893 m_departure_tree.hilite_item(i);
898 } else { // no ships selected, 0 or more player ships selected
899 if (player_count > 1) { // multiple player ships selected
900 SDL_assert(base_player >= 0);
901 m_ship_name = _T("");
902 m_player_ship.SetCheck(TRUE);
903 objp = GET_FIRST(&obj_used_list);
904 while (objp != END_OF_LIST(&obj_used_list)) {
905 if ((objp->type == OBJ_START) && (objp->flags & OF_MARKED)) {
907 if (base_player >= 0) {
908 m_ship_class = Ships[i].ship_info_index;
909 m_team = bitmask_2_bitnum(Ships[i].team);
913 if (Ships[i].ship_info_index != m_ship_class)
915 if (bitmask_2_bitnum(Ships[i].team) != m_team)
920 objp = GET_NEXT(objp);
923 // only 1 player selected..
924 } else if (query_valid_object() && (Objects[cur_object_index].type == OBJ_START)) {
925 SDL_assert((player_count == 1) && !multi_edit);
926 player_ship = Objects[cur_object_index].instance;
927 m_ship_name = Ships[player_ship].ship_name;
928 m_ship_class = Ships[player_ship].ship_info_index;
929 m_team = bitmask_2_bitnum(Ships[player_ship].team);
930 m_player_ship.SetCheck(TRUE);
932 } else { // no ships or players selected..
933 m_ship_name = _T("");
937 m_player_ship.SetCheck(FALSE);
943 m_score.blank(); // cause control to be blank
944 m_arrival_location = -1;
945 m_departure_location = -1;
946 m_arrival_delay.blank();
947 m_departure_delay.blank();
948 m_arrival_dist.blank();
949 m_arrival_target = -1;
950 m_departure_target = -1;
951 m_arrival_tree.clear_tree();
952 m_arrival_tree.DeleteAllItems();
953 m_departure_tree.clear_tree();
954 m_departure_tree.DeleteAllItems();
955 m_no_arrival_warp.SetCheck(0);
956 m_no_departure_warp.SetCheck(0);
957 enable = p_enable = 0;
958 GetDlgItem(IDC_WING)->SetWindowText(_T("None"));
961 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
962 // must put the appropriate ships into the list depending on arrival location
963 if ( m_arrival_location != ARRIVE_FROM_DOCK_BAY ){
964 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
966 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
969 // set the internal variable appropriatly
970 if (m_arrival_target >= SPECIAL_ARRIVAL_ANCHORS_OFFSET){
971 m_arrival_target -= SPECIAL_ARRIVAL_ANCHORS_OFFSET;
972 } else if (m_arrival_target >= 0) {
973 m_arrival_target = box->FindStringExact(-1, Ships[m_arrival_target].ship_name);
976 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
977 // must put the appropriate ships into the list depending on departure location
978 if ( m_departure_location == DEPART_AT_DOCK_BAY ){
979 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
984 if ( m_departure_target >= 0 ){
985 m_departure_target = box->FindStringExact( -1, Ships[m_departure_target].ship_name );
990 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
991 if (!mission_type){ // multiplayer mission
992 box->EnableWindow(TRUE);
996 box->EnableWindow(FALSE);
1000 box->ResetContent();
1001 for (i=0; i<2; i++) // hard coded: only allow friendly and hostile
1002 box->AddString(Team_names[i]);
1004 box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM);
1005 box->EnableWindow(enable);
1006 box->ResetContent();
1007 for (i=0; i<Num_team_names; i++){
1008 box->AddString(Team_names[i]);
1013 m_arrival_dist.display();
1014 m_arrival_delay.display();
1015 m_departure_delay.display();
1021 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(FALSE);
1022 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(FALSE);
1023 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1024 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1025 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(FALSE);
1026 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(FALSE);
1027 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(FALSE);
1028 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1029 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(FALSE);
1030 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(FALSE);
1031 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(FALSE);
1032 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(FALSE);
1033 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(FALSE);
1036 GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable);
1037 if (m_arrival_location) {
1038 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable);
1039 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable);
1041 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1042 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1045 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1046 if ( m_departure_location ) {
1047 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
1049 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1052 GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(enable);
1053 GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(enable);
1054 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
1055 GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
1056 GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable);
1057 GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable);
1058 GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable);
1059 GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable);
1060 GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable);
1064 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(!multi_edit);
1065 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(TRUE);
1066 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
1067 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(TRUE);
1068 GetDlgItem(IDC_WEAPONS)->EnableWindow(m_ship_class >= 0);
1069 GetDlgItem(IDC_FLAGS)->EnableWindow(TRUE);
1072 GetDlgItem(IDC_SHIP_NAME)->EnableWindow(FALSE);
1073 GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(FALSE);
1074 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
1075 GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(FALSE);
1076 GetDlgItem(IDC_WEAPONS)->EnableWindow(FALSE);
1077 GetDlgItem(IDC_FLAGS)->EnableWindow(FALSE);
1080 GetDlgItem(IDC_AI_CLASS)->EnableWindow(enable);
1081 GetDlgItem(IDC_SHIP_CARGO1)->EnableWindow(enable);
1082 GetDlgItem(IDC_HOTKEY)->EnableWindow(enable);
1083 if ((m_ship_class >= 0) && !(Ship_info[m_ship_class].flags & SIF_CARGO) && !(Ship_info[m_ship_class].flags & SIF_NO_SHIP_TYPE))
1084 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1085 else if (multi_edit)
1086 GetDlgItem(IDC_GOALS)->EnableWindow(enable);
1088 GetDlgItem(IDC_GOALS)->EnableWindow(FALSE);
1090 // !pship_count used because if allowed to clear, we would have no player starts
1091 if (mission_type || !pship_count || (pship_count + total_count > MAX_PLAYERS) || (pvalid_count < total_count))
1092 m_player_ship.EnableWindow(FALSE);
1094 m_player_ship.EnableWindow(TRUE);
1096 GetDlgItem(IDC_DELETE_SHIP)->EnableWindow(enable);
1097 GetDlgItem(IDC_SHIP_RESET)->EnableWindow(enable);
1098 GetDlgItem(IDC_SCORE)->EnableWindow(enable);
1101 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(m_ship_class >= 0);
1103 GetDlgItem(IDC_SHIP_TBL)->EnableWindow(0);
1104 GetDlgItem(IDC_SHIP_TBL)->ShowWindow(SW_HIDE);
1107 if (cue_init > 1) { // more than one ship (players don't have cues to edit)
1108 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_SHOW);
1109 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_SHOW);
1112 GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_HIDE);
1113 GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_HIDE);
1116 if (multi_edit || (total_count > 1)) {
1117 // we will allow the ignore orders dialog to be multi edit if all selected
1118 // ships are the same type. the ship_type (local) variable holds the ship types
1119 // for all ships. Determine how may bits set and enable/diable window
1121 if ( /*(m_team == -1) ||*/ (ship_orders == -1) ){
1122 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(FALSE);
1124 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(TRUE);
1127 // always enabled when one ship is selected
1128 GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(enable);
1130 // always enabled if >= 1 ship selected
1131 GetDlgItem(IDC_SHIP_PERSONA)->EnableWindow(enable);
1134 SetWindowText("Edit Marked Ships");
1135 } else if (player_count) {
1136 SetWindowText("Edit Player Ship");
1138 SetWindowText("Edit Ship");
1141 // setup alternate name stuff
1142 if(player_ship >= 0){
1143 ship_alt_name_init(player_ship);
1145 ship_alt_name_init(single_ship);
1154 // update ship structure(s) with dialog data. The data is first checked for errors. If
1155 // no errors occur, returns 0. If an error occurs, returns -1. If the update is bypassed,
1156 // returns 1. Bypass is necessary to avoid an infinite loop, and it doesn't actually
1157 // update the data. Bypass only occurs if bypass mode is active and we still get an error.
1158 // Once the error no longer occurs, bypass mode is cleared and data is updated.
1159 int CShipEditorDlg::update_data(int redraw)
1161 char *str, old_name[255];
1164 CSingleLock sync(&CS_cur_object_index), sync2(&CS_update);
1166 nprintf(("Fred routing", "Ship dialog save\n"));
1167 if (!GetSafeHwnd() || !initialized || bypass_all)
1170 sync.Lock(); // don't allow cur_object_index to change while we are using it
1171 sync2.Lock(); // don't allow reinitialization until we are done updating
1174 Wing_editor_dialog.update_data_safe();
1175 if (multi_edit) { // editing multiple ships (ships and/or players)
1176 ptr = GET_FIRST(&obj_used_list);
1177 while (ptr != END_OF_LIST(&obj_used_list)) {
1178 if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags & OF_MARKED))
1179 update_ship(get_ship_from_obj(ptr));
1181 ptr = GET_NEXT(ptr);
1184 } else if (player_ship >= 0) { // editing a single player
1185 update_ship(player_ship);
1187 } else if (single_ship >= 0) { // editing a single ship
1188 ptr = GET_FIRST(&obj_used_list);
1189 while (ptr != END_OF_LIST(&obj_used_list)) {
1190 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (cur_object_index != OBJ_INDEX(ptr))) {
1191 str = Ships[ptr->instance].ship_name;
1192 if (!stricmp(m_ship_name, str)) {
1197 z = MessageBox("This ship name is already being used by another ship\n"
1198 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1203 m_ship_name = _T(Ships[single_ship].ship_name);
1208 ptr = GET_NEXT(ptr);
1211 for (i=0; i<MAX_WINGS; i++)
1212 if (Wings[i].wave_count && !stricmp(Wings[i].name, m_ship_name)) {
1217 z = MessageBox("This ship name is already being used by a wing\n"
1218 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1223 m_ship_name = _T(Ships[single_ship].ship_name);
1227 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
1228 if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_ship_name)) {
1233 z = MessageBox("This ship name is already being used by a waypoint path\n"
1234 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1239 m_ship_name = _T(Ships[single_ship].ship_name);
1243 for (i=0; i<Num_jump_nodes; i++)
1244 if (!stricmp(Jump_nodes[i].name, m_ship_name)) {
1249 z = MessageBox("This ship name is already being used by a jump node\n"
1250 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
1255 m_ship_name = _T(Ships[single_ship].ship_name);
1259 wing = Ships[single_ship].wingnum;
1261 SDL_assert((wing < MAX_WINGS) && Wings[wing].wave_count);
1262 for (i=0; i<Wings[wing].wave_count; i++)
1263 if (wing_objects[wing][i] == Ships[single_ship].objnum)
1266 SDL_assert(i < Wings[wing].wave_count);
1267 sprintf(old_name, "%s %d", Wings[wing].name, i + 1);
1268 if (stricmp(old_name, m_ship_name)) {
1272 if (MessageBox("This ship is part of a wing, and it's name cannot be changed",
1273 NULL, MB_OKCANCEL) == IDCANCEL)
1276 m_ship_name = _T(old_name);
1281 z = update_ship(single_ship);
1285 strcpy(old_name, Ships[single_ship].ship_name);
1286 string_copy(Ships[single_ship].ship_name, m_ship_name, NAME_LENGTH, 1);
1287 str = Ships[single_ship].ship_name;
1288 if (stricmp(old_name, str)) {
1289 update_sexp_references(old_name, str);
1290 ai_update_goal_references(REF_TYPE_SHIP, old_name, str);
1291 for (i=0; i<Num_reinforcements; i++)
1292 if (!stricmp(old_name, Reinforcements[i].name)) {
1293 SDL_assert(strlen(str) < NAME_LENGTH);
1294 strcpy(Reinforcements[i].name, str);
1301 if (Player_start_shipnum < 0 || Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) { // need a new single player start.
1302 ptr = GET_FIRST(&obj_used_list);
1303 while (ptr != END_OF_LIST(&obj_used_list)) {
1304 if (ptr->type == OBJ_START) {
1305 Player_start_shipnum = ptr->instance;
1309 ptr = GET_NEXT(ptr);
1316 Wing_editor_dialog.initialize_data_safe(1);
1321 update_map_window();
1326 int CShipEditorDlg::update_ship(int ship)
1333 // THIS DIALOG IS THE SOME OF THE WORST CODE I HAVE EVER SEEN IN MY ENTIRE LIFE.
1334 // IT TOOK A RIDICULOUSLY LONG AMOUNT OF TIME TO ADD 2 FUNCTIONS. OMG
1335 ship_alt_name_close(ship);
1337 if ((Ships[ship].ship_info_index != m_ship_class) && (m_ship_class != -1)) {
1338 change_ship_type(ship, m_ship_class);
1343 MODIFY(Ships[ship].team, 1 << m_team);
1345 if (Objects[Ships[ship].objnum].type != OBJ_SHIP){
1346 if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)){
1351 if (m_ai_class != -1){
1352 MODIFY(Ships[ship].weapons.ai_class, m_ai_class);
1354 if (strlen(m_cargo1)) {
1355 z = string_lookup(m_cargo1, Cargo_names, Num_cargo);
1357 SDL_assert(Num_cargo < MAX_CARGO);
1359 strcpy(Cargo_names[z], m_cargo1);
1362 MODIFY(Ships[ship].cargo1, (char)z);
1365 m_score.save(&Ships[ship].score);
1366 if (m_arrival_location != -1)
1367 MODIFY(Ships[ship].arrival_location, m_arrival_location);
1368 if (m_departure_location != -1)
1369 MODIFY(Ships[ship].departure_location, m_departure_location);
1371 // do the persona update
1372 // m_persona holds the index into the list. Get the item data associated with this index and then
1373 // assign to the ship taking care that we check for the NO_PERSONA_INDEX id
1374 box = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA);
1375 persona = box->GetItemData(m_persona);
1376 if ( persona == NO_PERSONA_INDEX )
1379 MODIFY(Ships[ship].persona_index, persona);
1381 if (Ships[ship].wingnum < 0) {
1382 if (!multi_edit || m_update_arrival) { // should we update the arrival cue?
1383 if (Ships[ship].arrival_cue >= 0)
1384 free_sexp2(Ships[ship].arrival_cue);
1386 Ships[ship].arrival_cue = m_arrival_tree.save_tree();
1389 if (!multi_edit || m_update_departure) {
1390 if (Ships[ship].departure_cue >= 0)
1391 free_sexp2(Ships[ship].departure_cue);
1393 Ships[ship].departure_cue = m_departure_tree.save_tree();
1396 m_arrival_dist.save(&Ships[ship].arrival_distance);
1397 m_arrival_delay.save(&Ships[ship].arrival_delay);
1398 m_departure_delay.save(&Ships[ship].departure_delay);
1399 if (m_arrival_target >= 0) {
1400 z = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
1401 MODIFY(Ships[ship].arrival_anchor, z);
1403 // if the arrival is not hyperspace or docking bay -- force arrival distance to be
1404 // greater than 2*radius of target.
1405 if (((m_arrival_location != ARRIVE_FROM_DOCK_BAY) && (m_arrival_location != ARRIVE_AT_LOCATION)) && (z >= 0) && (z < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
1406 d = int(min(500, 2.0f * Objects[Ships[ship].objnum].radius));
1407 if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) {
1408 str.Format("Ship must arrive at least %d meters away from target.\n"
1409 "Value has been reset to this. Use with caution!\r\n"
1410 "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[ship].objnum].radius) );
1413 if (Ships[ship].arrival_distance < 0)
1414 Ships[ship].arrival_distance = -d;
1416 Ships[ship].arrival_distance = d;
1418 m_arrival_dist.fix(Ships[ship].arrival_distance);
1422 z = ((CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
1423 MODIFY(Ships[ship].departure_anchor, z );
1427 MODIFY(Ships[ship].hotkey, m_hotkey - 1);
1429 switch( m_no_arrival_warp.GetCheck() ) {
1431 if (Ships[ship].flags & SF_NO_ARRIVAL_WARP)
1434 Ships[ship].flags &= ~SF_NO_ARRIVAL_WARP;
1438 if (!(Ships[ship].flags & SF_NO_ARRIVAL_WARP))
1441 Ships[ship].flags |= SF_NO_ARRIVAL_WARP;
1445 switch( m_no_departure_warp.GetCheck() ) {
1447 if (Ships[ship].flags & SF_NO_DEPARTURE_WARP)
1450 Ships[ship].flags &= ~SF_NO_DEPARTURE_WARP;
1454 if (!(Ships[ship].flags & SF_NO_DEPARTURE_WARP))
1457 Ships[ship].flags |= SF_NO_DEPARTURE_WARP;
1461 switch (m_player_ship.GetCheck()) {
1463 if (Objects[Ships[ship].objnum].type != OBJ_START) {
1468 Objects[Ships[ship].objnum].type = OBJ_START;
1472 if (Objects[Ships[ship].objnum].type == OBJ_START) {
1477 Objects[Ships[ship].objnum].type = OBJ_SHIP;
1485 void CShipEditorDlg::OnOK()
1493 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
1498 void CShipEditorDlg::OnInitMenu(CMenu *pMenu)
1502 m = pMenu->GetSubMenu(0);
1504 generate_ship_popup_menu(m, ID_SHIP_MENU, MF_ENABLED, SHIP_FILTER_PLAYERS);
1506 m->CheckMenuItem(ID_SHIP_MENU + cur_ship, MF_BYCOMMAND | MF_CHECKED);
1508 CWnd::OnInitMenu(pMenu);
1511 BOOL CShipEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam)
1515 id = LOWORD(wParam);
1516 if (id >= ID_SHIP_MENU && id < ID_SHIP_MENU + MAX_SHIPS) {
1517 if (!update_data()) {
1518 ship = id - ID_SHIP_MENU;
1520 set_cur_object_index(Ships[ship].objnum);
1525 return CDialog::OnCommand(wParam, lParam);
1528 void CShipEditorDlg::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1530 m_arrival_tree.right_clicked();
1534 void CShipEditorDlg::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1536 m_departure_tree.right_clicked();
1540 void CShipEditorDlg::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1542 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1544 if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1546 modified = editing = 1;
1552 void CShipEditorDlg::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1554 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1556 if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1558 modified = editing = 1;
1564 void CShipEditorDlg::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1566 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1568 *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1572 void CShipEditorDlg::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1574 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1576 *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1580 int CShipEditorDlg::verify()
1582 nprintf(("Fred routing", "Ship dialog verify\n"));
1583 if (!GetSafeHwnd() || !modified)
1592 void CShipEditorDlg::OnGoals()
1594 ShipGoalsDlg dlg_goals;
1596 SDL_assert(query_valid_object());
1598 // dlg_goals.initialize_multi();
1601 // SDL_assert(single_ship != -1);
1602 // dlg_goals.self_ship = single_ship;
1603 // dlg_goals.initialize(Ai_info[Ships[single_ship].ai_index].goals);
1607 SDL_assert(single_ship != -1);
1608 dlg_goals.self_ship = single_ship;
1611 dlg_goals.DoModal();
1612 if (!multi_edit && !query_initial_orders_empty(Ai_info[Ships[single_ship].ai_index].goals))
1613 if ((Ships[single_ship].wingnum >= 0) && (query_initial_orders_conflict(Ships[single_ship].wingnum)))
1614 MessageBox("This ship's wing also has initial orders", "Possible conflict");
1617 void CShipEditorDlg::OnSelchangeShipClass()
1623 ptr = GET_FIRST(&obj_used_list);
1624 while (ptr != END_OF_LIST(&obj_used_list)) {
1625 if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags & OF_MARKED))
1626 if (Ships[ptr->instance].ship_info_index != m_ship_class) {
1627 change_ship_type(ptr->instance, m_ship_class);
1631 ptr = GET_NEXT(ptr);
1634 update_map_window();
1637 void CShipEditorDlg::OnInitialStatus()
1641 dlg.m_multi_edit = multi_edit;
1645 void CShipEditorDlg::OnWeapons()
1648 WeaponEditorDlg dlg;
1652 dlg.m_multi_edit = multi_edit;
1656 objp = GET_FIRST(&obj_used_list);
1657 while (objp != END_OF_LIST(&obj_used_list)) {
1658 if (objp->flags & OF_MARKED)
1659 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
1662 if (Ships[i].weapons.ai_class != Ships[ship].weapons.ai_class)
1667 m_ai_class = Ships[i].weapons.ai_class;
1671 objp = GET_NEXT(objp);
1679 SDL_assert(ship >= 0);
1680 m_ai_class = Ships[ship].weapons.ai_class;
1683 box = (CComboBox *) GetDlgItem(IDC_AI_CLASS);
1684 box->SetCurSel(m_ai_class);
1687 void CShipEditorDlg::OnShipReset()
1689 int i, j, index, ship;
1694 model_subsystem *sp;
1696 m_cargo1 = "Nothing";
1697 m_ai_class = AI_DEFAULT_CLASS;
1699 if (Ship_info[m_ship_class].species == SPECIES_SHIVAN)
1700 m_team = TEAM_HOSTILE;
1702 m_team = TEAM_FRIENDLY;
1705 objp = GET_FIRST(&obj_used_list);
1706 while (objp != END_OF_LIST(&obj_used_list)) {
1707 if (((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) && (objp->flags & OF_MARKED)) {
1708 ship = objp->instance;
1711 for (i=0; i<MAX_AI_GOALS; i++){
1712 Ai_info[Ships[ship].ai_index].goals[i].ai_mode = AI_GOAL_NONE;
1715 objp->phys_info.speed = 0.0f;
1716 objp->shields[0] = 100.0f;
1717 objp->hull_strength = 100.0f;
1719 sip = &Ship_info[Ships[ship].ship_info_index];
1720 for (i=0; i<sip->num_primary_banks; i++)
1721 Ships[ship].weapons.primary_bank_weapons[i] = sip->primary_bank_weapons[i];
1723 for (i=0; i<sip->num_secondary_banks; i++) {
1724 Ships[ship].weapons.secondary_bank_weapons[i] = sip->secondary_bank_weapons[i];
1725 Ships[ship].weapons.secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i];
1729 ptr = GET_FIRST(&Ships[ship].subsys_list);
1730 while (ptr != END_OF_LIST(&Ships[ship].subsys_list)) {
1731 ptr->current_hits = 0.0f;
1732 if (ptr->system_info->type == SUBSYSTEM_TURRET) {
1734 sp = &Ship_info[Ships[ship].ship_info_index].subsystems[index];
1737 for (i=0; i<MAX_PRIMARY_BANKS; i++){
1738 if (sp->primary_banks[i] != -1){
1739 wp->primary_bank_weapons[j++] = sp->primary_banks[i];
1743 wp->num_primary_banks = j;
1745 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1746 if (sp->secondary_banks[i] != -1) {
1747 wp->secondary_bank_weapons[j] = sp->secondary_banks[i];
1748 wp->secondary_bank_capacity[j++] = sp->secondary_bank_capacity[i];
1752 wp->num_secondary_banks = j;
1753 for (i=0; i<MAX_SECONDARY_BANKS; i++){
1754 wp->secondary_bank_ammo[i] = 100;
1759 ptr = GET_NEXT(ptr);
1763 objp = GET_NEXT(objp);
1768 MessageBox("Ships reset to ship class defaults");
1770 MessageBox("Ship reset to ship class defaults");
1774 void CShipEditorDlg::OnDeleteShip()
1780 void CShipEditorDlg::OnShipTbl()
1784 dlg.set(m_ship_class);
1788 int CShipEditorDlg::make_ship_list(int *arr)
1793 ptr = GET_FIRST(&obj_used_list);
1794 while (ptr != END_OF_LIST(&obj_used_list)) {
1795 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)){
1796 arr[n++] = OBJ_INDEX(ptr);
1799 ptr = GET_NEXT(ptr);
1805 void CShipEditorDlg::OnPrev()
1807 int i, n, arr[MAX_SHIPS];
1809 if (!update_data()) {
1810 n = make_ship_list(arr);
1820 for (i=0; i<n; i++){
1821 if (Ships[cur_ship].objnum == arr[i]){
1834 set_cur_object_index(arr[i]);
1835 Ship_editor_dialog.initialize_data(1);
1842 void CShipEditorDlg::OnNext()
1844 int i, n, arr[MAX_SHIPS];
1846 if (!update_data()) {
1847 n = make_ship_list(arr);
1856 if (Ships[cur_ship].objnum == arr[i])
1866 set_cur_object_index(arr[i]);
1867 Ship_editor_dialog.initialize_data(1);
1874 void CShipEditorDlg::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1878 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1879 h = pNMTreeView->itemNew.hItem;
1881 m_arrival_tree.update_help(h);
1887 void CShipEditorDlg::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1891 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1892 h = pNMTreeView->itemNew.hItem;
1894 m_departure_tree.update_help(h);
1900 void CShipEditorDlg::calc_cue_height()
1904 GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1905 cue_height = cue.bottom - cue.top + 10;
1906 if (Show_sexp_help){
1907 cue_height += SEXP_HELP_BOX_SIZE;
1910 if (Hide_ship_cues) {
1911 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1916 void CShipEditorDlg::show_hide_sexp_help()
1920 if (Show_sexp_help){
1921 cue_height += SEXP_HELP_BOX_SIZE;
1923 cue_height -= SEXP_HELP_BOX_SIZE;
1926 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()){
1930 GetWindowRect(rect);
1932 if (Show_sexp_help){
1933 rect.bottom += SEXP_HELP_BOX_SIZE;
1935 rect.bottom -= SEXP_HELP_BOX_SIZE;
1941 void CShipEditorDlg::OnHideCues()
1945 GetWindowRect(rect);
1946 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1947 rect.bottom -= cue_height;
1951 rect.bottom += cue_height;
1958 void CShipEditorDlg::OnSelchangeArrivalLocation()
1963 box = (CComboBox *)GetDlgItem( IDC_ARRIVAL_TARGET );
1964 if (m_arrival_location) {
1965 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE);
1966 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE);
1967 if (m_arrival_target < 0) {
1968 m_arrival_target = 0;
1971 // determine which items we should put into the arrival target combo box
1972 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
1973 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1975 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1979 m_arrival_target = -1;
1980 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1981 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1986 void CShipEditorDlg::OnSelchangeDepartureLocation()
1991 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1992 if ( m_departure_location ) {
1993 box->EnableWindow(TRUE);
1994 if ( m_departure_target < 0 ) {
1995 m_departure_target = 0;
1998 // we need to build up the list box content based on the departure type. When
1999 // from a docking bay, only show ships in the list which have them. Show all ships otherwise
2000 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
2001 management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
2003 // I think that this section is currently illegal
2008 m_departure_target = -1;
2009 box->EnableWindow(FALSE);
2015 void CShipEditorDlg::OnPlayerShip()
2017 if (m_player_ship.GetCheck() == 1)
2018 m_player_ship.SetCheck(0);
2020 m_player_ship.SetCheck(1);
2022 update_map_window();
2025 void CShipEditorDlg::OnNoArrivalWarp()
2027 if (m_no_arrival_warp.GetCheck() == 1)
2028 m_no_arrival_warp.SetCheck(0);
2030 m_no_arrival_warp.SetCheck(1);
2033 void CShipEditorDlg::OnNoDepartureWarp()
2035 if (m_no_departure_warp.GetCheck() == 1)
2036 m_no_departure_warp.SetCheck(0);
2038 m_no_departure_warp.SetCheck(1);
2042 // function to possibly warn user when he selects a hotkey which might be used for
2044 void CShipEditorDlg::OnSelchangeHotkey()
2050 set_num = m_hotkey-1; // use -1 since values associated with hotkey sets are 1 index based
2052 // the first three sets are generally reserved for player starting wings.
2053 if ( set_num < MAX_STARTING_WINGS ) {
2054 sprintf( buf, "This hotkey set should probably be reserved\nfor wing %s", Starting_wing_names[set_num] );
2055 MessageBox(buf, NULL, MB_OK);
2059 void CShipEditorDlg::OnFlags()
2063 dlg.setup(p_enable);
2067 void CShipEditorDlg::OnIgnoreOrders()
2069 // TODO: Add your control notification handler code here
2070 ignore_orders_dlg player_order_dlg;
2072 SDL_assert(query_valid_object());
2075 if ( single_ship != -1 ){
2076 player_order_dlg.m_ship = single_ship;
2078 player_order_dlg.m_ship = player_ship;
2081 player_order_dlg.m_ship = -1;
2084 player_order_dlg.DoModal();
2087 void CShipEditorDlg::OnSpecialExp()
2089 // TODO: Add your control notification handler code here
2090 ShipSpecialDamage dlg;
2094 // alternate ship name stuff
2095 void CShipEditorDlg::ship_alt_name_init(int base_ship)
2098 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2106 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE);
2109 GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE);
2111 // reset the combobox and add all relevant strings
2112 ptr->ResetContent();
2113 ptr->AddString("<none>");
2114 for(idx=0; idx<Mission_alt_type_count; idx++){
2115 ptr->AddString(Mission_alt_types[idx]);
2123 // otherwise look his stuff up
2124 if(strlen(Fred_alt_names[base_ship])){
2125 ptr->SelectString(0, Fred_alt_names[base_ship]);
2131 void CShipEditorDlg::ship_alt_name_close(int base_ship)
2134 char str[NAME_LENGTH+2] = "";
2136 CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT);
2147 // see if we have something besides "none" selected
2148 ptr->GetWindowText(cstr);
2149 if(cstr == CString("<none>")){
2151 strcpy(Fred_alt_names[base_ship], "");
2155 p = cstr.GetBuffer(0);
2161 // otherwise see if it already exists
2162 if(mission_parse_lookup_alt(str) >= 0){
2163 strcpy(Fred_alt_names[base_ship], str);
2168 // otherwise try and add it
2169 if(mission_parse_add_alt(str) >= 0){
2170 strcpy(Fred_alt_names[base_ship], str);
2175 // bad - couldn't add
2176 strcpy(Fred_alt_names[base_ship], "");
2177 MessageBox("Couldn't add new alternate type name. Already using too many!");