/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/fred2/ShipEditorDlg.cpp $ * $Revision: 1.13 $ * $Date: 2007-09-03 01:02:49 $ * $Author: Goober5000 $ * * Single ship editing dialog * * $Log: not supported by cvs2svn $ * Revision 1.12 2007/02/11 21:26:34 Goober5000 * massive shield infrastructure commit * * Revision 1.11 2007/01/29 03:39:25 Goober5000 * --fix the empty ship name / U.R.A. Moron bug caused by WMC's commit * --properly update a ship score when its class changes (in FRED or via change-ship-class or via ship loadout) * * Revision 1.10 2006/12/28 00:59:20 wmcoolmon * WMC codebase commit. See pre-commit build thread for details on changes. * * Revision 1.9 2006/11/03 21:36:56 karajorma * Fix for Mantis 1017. - Hope we've seen the end of that damn persona bug * * Revision 1.8 2006/07/30 20:01:56 Kazan * resolve 1018 and an interface problem in fred2's ship editor * * Revision 1.7 2006/06/04 01:01:52 Goober5000 * add fighterbay restriction code * --Goober5000 * * Revision 1.6 2006/06/02 09:48:38 karajorma * Added the alt ship class button * * Revision 1.5 2006/05/30 05:37:29 Goober5000 * add capability to restrict arrival/departure paths * (FRED only; FS2 implementation to follow) * --Goober5000 * * Revision 1.4 2006/04/20 06:32:01 Goober5000 * proper capitalization according to Volition * * Revision 1.3 2006/04/18 00:08:23 phreak * fix FRED crashing if the user adds multiple waypoint paths then inserts more ships. * * Revision 1.2 2006/02/04 07:05:03 Goober5000 * fixed several IFF bugs in FRED (plus one or two other bugs) * --Goober5000 * * Revision 1.1 2006/01/19 02:27:31 Goober5000 * import FRED2 back into fs2_open module * --Goober5000 * * Revision 1.20 2006/01/14 23:49:01 Goober5000 * second pass; all the errors are fixed now; one more thing to take care of * --Goober5000 * * Revision 1.19 2006/01/14 05:24:19 Goober5000 * first pass at converting FRED to use new IFF stuff * --Goober5000 * * Revision 1.18 2005/12/29 08:21:00 wmcoolmon * No my widdle FRED, I didn't forget about you ^_^ (codebase commit) * * Revision 1.17 2005/09/26 07:58:27 Goober5000 * hooray, more custom wing fixes * --Goober5000 * * Revision 1.16 2005/09/26 07:22:25 Goober5000 * small tweak to finish the fix * --Goober5000 * * Revision 1.15 2005/09/26 03:37:35 Goober5000 * species upgrade stuff for FRED * --Goober5000 * * Revision 1.14 2005/08/23 07:28:02 Goober5000 * grammar * --Goober5000 * * Revision 1.13 2005/07/15 21:07:01 Goober5000 * fixed a bunch of stupid errors that never should have made it to CVS * --Goober5000 * * Revision 1.12 2005/07/13 01:03:10 Goober5000 * improved species support and removed need for #define * --Goober5000 * * Revision 1.11 2005/06/29 19:00:25 taylor * some departure target fixes: * - the ships editor was just plain wrong since it wouldn't properly add ships to the departure target list * - the wing editor tried to set the departure target before having a list to set with * * Revision 1.10 2005/03/29 03:43:11 phreak * ai directory fixes as well as fixes for the new jump node code * * Revision 1.9 2005/03/06 22:43:14 wmcoolmon * Fixx0red some of the jump node errors * * Revision 1.8 2004/12/15 19:16:13 Goober5000 * FRED code for custom wing names * --Goober5000 * * Revision 1.7 2004/06/15 20:50:29 wmcoolmon * hud-set-color, current-speed, and FRED fixes (Wouldn't compile). * * Revision 1.6 2003/09/05 06:53:41 Goober5000 * added code to change the player's ship in single player * --Goober5000 * * Revision 1.5 2003/04/29 01:04:28 Goober5000 * custom hitpoints for FRED * --Goober5000 * * Revision 1.4 2003/03/25 07:03:29 Goober5000 * added beginning functionality for $Texture Replace implementation in FRED * --Goober5000 * * Revision 1.3 2002/12/17 03:16:11 DTP * made TBL button in initial_ship status, accisible while running a release build or debug build. * * Revision 1.2 2002/08/15 01:06:34 penguin * Include filename reorg (to coordinate w/ fs2_open) * * Revision 1.1.1.1 2002/07/15 03:11:03 inquisitor * Initial FRED2 Checking * * * 8 8/18/99 1:32p Andsager * Mark Vasudan wingmen as such. * * 7 8/18/99 1:12p Andsager * Allow ships to be assigned Vasudan persona (wingman 6) * * 6 8/16/99 10:52p Andsager * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals. * * 5 8/11/99 9:27a Andsager * Fix compile warning. * * 4 5/20/99 6:59p Dave * Added alternate type names for ships. Changed swarm missile table * entries. * * 3 2/11/99 2:15p Andsager * Add ship explosion modification to FRED * * 2 10/07/98 6:28p Dave * Initial checkin. Renamed all relevant stuff to be Fred2 instead of * Fred. Globalized mission and campaign file extensions. Removed Silent * Threat specific code. * * 1 10/07/98 3:02p Dave * * 1 10/07/98 3:00p Dave * * 157 6/16/98 10:17a Hoffoss * Fixed define that was backwards and no one caught before release (ya, * great testing..) * * 156 5/23/98 3:33p Hoffoss * Removed unused code in reinforcements editor and make ships.tbl button * in ship editor disappear in release build. * * 155 5/21/98 12:58a Hoffoss * Fixed warnings optimized build turned up. * * 154 4/28/98 2:13p Hoffoss * Added code to help keep invalid player ship types from existing in * mission. * * 153 4/24/98 2:57p Jim * Fixed typo in code. * * 152 4/22/98 11:55a Hoffoss * Fixed bug with ship editor's hide cue button when sexp help is on at * startup. * * 151 4/16/98 5:59p Duncan * Fixed bad assumption, apparently. * * 150 4/07/98 9:42a Allender * put in persona combo box into ship editor. Removed code to assign * personas based on message * * 149 3/30/98 1:15p Hoffoss * Fixed bug with arrival/departure cue window size calculation. Wasn't * working anymore after my changes to dialog initing at startup. * * 148 3/27/98 12:02p Sandeep * * 147 3/25/98 4:14p Hoffoss * Split ship editor up into ship editor and a misc dialog, which tracks * flags and such. * * 146 3/21/98 7:36p Lawrance * Move jump nodes to own lib. * * 145 3/16/98 8:27p Allender * Fred support for two new AI flags -- kamikaze and no dynamic goals. * * 144 3/10/98 6:11p Hoffoss * Added jump node renaming abilities to Fred. * * 143 3/09/98 4:30p Allender * multiplayer secondary weapon changes. red-alert and cargo-known-delay * sexpressions. Add time cargo revealed to ship structure * * 142 2/22/98 1:21a Hoffoss * Disabled weapon editor if mutliple ship types marked. * * 141 2/17/98 12:07p Hoffoss * Changed over to using SF_CARGO_REVEALED in fred. * * 140 2/17/98 11:42a Hoffoss * Added support for hidden from sensors condition. * * 139 2/13/98 2:42p Duncan * Fixed bug, moved line down where it needs to be because * pre-initializations need to be done first. * * 138 2/10/98 1:42p Allender * allow > MAX_ESCORT_SHIPS to be marked as escort ships * * 137 2/06/98 2:54p Hoffoss * Fixed some bugs in dialog init, and cleared up some of the confusion * about how it works by renaming some variables and adding comments. * * 136 2/06/98 10:48a Hoffoss * Fixed bug with not being able to make ships players in multi mode * missions. * * 135 2/04/98 4:32p Allender * support for multiple briefings and debriefings. Changes to mission * type (now a bitfield). Bitfield defs for multiplayer modes * * 134 1/29/98 5:14p Hoffoss * Added support for a SF_INVULNERABLE ship flag in Fred. * * 133 1/12/98 10:41a Allender * fixed minor bug with ship editor and ignore orders dialog * * 132 12/05/97 4:07p Hoffoss * Changed code to allow WHO_FROM type ship sources to only show flyable * ships in list. * * 131 11/24/97 2:31p Allender * allow ignore orders dialog to be active for players * * 130 11/24/97 9:07a Allender * ignore orders dialog should function as multi-edit now * * 129 11/22/97 4:17p Allender * first pass of making ignore orders dialog multi edit * * 128 11/13/97 4:14p Allender * automatic assignment of hotkeys for starting wings. Appripriate * warnings when they are incorrectly used. hotkeys correctly assigned to * ships/wing arriving after mission start * * 127 11/11/97 3:32p Johnson * allender: Combo boxes need to have lists initialized before setting * internal class variable for arrival/depature targets * * 126 11/11/97 2:13p Allender * docking bay support for Fred and FreeSpace. Added hook to ai code for * arrival/departure from dock bays. Fred support now sufficient. * * 125 11/10/97 10:13p Allender * added departure anchor to Fred and FreeSpace in preparation for using * docking bays. Functional in Fred, not in FreeSpace. * * 124 10/21/97 4:49p Allender * added flags to Fred and FreeSpace to forgo warp effect (toggle in ship * editor in Fred) * * 123 10/14/97 5:33p Hoffoss * Added Fred support (and fsm support) for the no_arrival_music flags in * ships and wings. * * 122 9/18/97 10:49a Allender * increment/decrement Player_start variable when making a ship a player * start * * 121 9/17/97 5:43p Hoffoss * Added Fred support for new player start information. * * 120 9/16/97 9:41p Hoffoss * Changed Fred code around to stop using Parse_player structure for * player information, and use actual ships instead. * * 119 9/15/97 2:35p Hoffoss * Fixed bug in Fred where a player ship and normal ship both marked * clobbered each other's ship type in ship editor dialog. * * 118 9/09/97 10:29a Hoffoss * Added support for neutral team, and fixed changes made to how team is * used in ship structure. * * 117 9/09/97 9:27a Hoffoss * Removed #Jason Hoffoss# comments from code. Code is already set up to * handle the situation properly. * * 116 9/06/97 2:13p Mike * Replace support for TEAM_NEUTRAL * * 115 9/04/97 5:35p Hoffoss * Fixed arrival distance stuff. * * 114 9/04/97 5:04p Johnson * Fixed bug with arrival target distance checking. * * 113 9/04/97 4:31p Hoffoss * Fixed bug: Changed ship editor to not touch wing info (arrival or * departure cues) to avoid conflicts with wing editor's changes. * * 112 8/30/97 9:52p Hoffoss * Implemented arrival location, distance, and anchor in Fred. * * 111 8/28/97 8:56a Hoffoss * Added more checking to sexp error checker, fixed some bugs. * * 110 8/25/97 5:56p Hoffoss * Added multiple asteroid field support, loading and saving of asteroid * fields, and ship score field to Fred. * * 109 8/22/97 4:16p Hoffoss * added support for arrival and departure info in ship editor using * wing's info if editing marked ships in a wing instead of using ship's. * * 108 8/21/97 11:37p Hoffoss * Fixed bug: when renaming a ship that is a reinforcement, an extra * instance of it is added to the reinforcement list. * * 107 8/20/97 6:53p Hoffoss * Implemented escort flag support in Fred. * * 106 8/19/97 2:53p Hoffoss * Fixed bug where multiple ships editing doesn't change players. * * 105 8/19/97 1:44p Hoffoss * Fixed bug with updating too quickly (i.e. via prev and next buttons). * * $NoKeywords: $ */ #include "stdafx.h" #include "FRED.h" #include "FREDDoc.h" #include "FREDView.h" #include "MainFrm.h" #include "render/3d.h" #include "physics/physics.h" #include "editor.h" #include "ai/ailocal.h" #include "ai/aigoals.h" #include "parse/parselo.h" #include "Management.h" #include "globalincs/linklist.h" #include "InitialStatus.h" #include "WeaponEditorDlg.h" #include "ship/ship.h" #include "TextViewDlg.h" #include "playerman/player.h" // used for the max_keyed_target stuff #include "IgnoreOrdersDlg.h" #include "mission/missionparse.h" #include "model/model.h" #include "starfield/starfield.h" #include "jumpnode/jumpnode.h" #include "ShipFlagsDlg.h" #include "mission/missionmessage.h" #include "ShipSpecialDamage.h" #include "ShipTexturesDlg.h" #include "ShipSpecialHitpoints.h" #include "AltShipClassDlg.h" #include "species_defs/species_defs.h" #include "iff_defs/iff_defs.h" #include "restrictpaths.h" #define ID_SHIP_MENU 9000 #define NO_PERSONA_INDEX 999 #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif void numeric_edit_control::setup(int id, CWnd *wnd) { control_id = id; dlg = wnd; } void numeric_edit_control::init(int n) { value = n; unique = 1; } void numeric_edit_control::set(int n) { if (n != value){ unique = 0; } } void numeric_edit_control::display() { CString str; if (unique){ str.Format("%d", value); } dlg->GetDlgItem(control_id)->SetWindowText(str); } void numeric_edit_control::save(int *n) { CString str; if (control_id) { dlg->GetDlgItem(control_id)->GetWindowText(str); if (!str.IsEmpty()){ MODIFY(*n, atoi(str)); } } } void numeric_edit_control::fix(int n) { if (unique) { CString str; CWnd *w; value = n; str.Format("%d", n); w = dlg->GetDlgItem(control_id); dlg->GetDlgItem(control_id)->SetWindowText(str); } } ///////////////////////////////////////////////////////////////////////////// // CShipEditorDlg dialog CShipEditorDlg::CShipEditorDlg(CWnd* pParent /*=NULL*/) : CDialog(CShipEditorDlg::IDD, pParent) { //{{AFX_DATA_INIT(CShipEditorDlg) m_ship_name = _T(""); m_cargo1 = _T(""); m_ship_class = -1; m_team = -1; m_arrival_location = -1; m_departure_location = -1; m_ai_class = -1; m_hotkey = -1; m_update_arrival = FALSE; m_update_departure = FALSE; m_arrival_target = -1; m_departure_target = -1; m_persona = -1; //}}AFX_DATA_INIT m_pSEView = NULL; initialized = editing = multi_edit = 0; select_sexp_node = -1; bypass_errors = 0; } // Modeless constructor, MK CShipEditorDlg::CShipEditorDlg(CView* pView) { m_pSEView = pView; initialized = editing = 0; select_sexp_node = -1; } void CShipEditorDlg::DoDataExchange(CDataExchange* pDX) { int n; CString str; CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CShipEditorDlg) DDX_Control(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp); DDX_Control(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp); DDX_Control(pDX, IDC_PLAYER_SHIP, m_player_ship); DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin); DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin); DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree); DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree); DDX_Text(pDX, IDC_SHIP_NAME, m_ship_name); DDX_CBString(pDX, IDC_SHIP_CARGO1, m_cargo1); DDX_CBIndex(pDX, IDC_SHIP_CLASS, m_ship_class); DDX_CBIndex(pDX, IDC_SHIP_TEAM, m_team); DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location); DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location); DDX_CBIndex(pDX, IDC_AI_CLASS, m_ai_class); DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey); DDX_Check(pDX, IDC_UPDATE_ARRIVAL, m_update_arrival); DDX_Check(pDX, IDC_UPDATE_DEPARTURE, m_update_departure); DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target); DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target); DDX_CBIndex(pDX, IDC_SHIP_PERSONA, m_persona); //}}AFX_DATA_MAP DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1); DDV_MaxChars(pDX, m_cargo1, NAME_LENGTH - 1); if (pDX->m_bSaveAndValidate) { // get dialog control values GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str); n = atoi(str); if (n < 0){ n = 0; } m_arrival_delay.init(n); GetDlgItem(IDC_ARRIVAL_DISTANCE)->GetWindowText(str); m_arrival_dist.init(atoi(str)); GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str); n = atoi(str); if (n < 0) n = 0; m_departure_delay.init(n); GetDlgItem(IDC_SCORE)->GetWindowText(str); m_score.init(atoi(str)); } } BEGIN_MESSAGE_MAP(CShipEditorDlg, CDialog) //{{AFX_MSG_MAP(CShipEditorDlg) ON_WM_CLOSE() ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree) ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree) ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree) ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree) ON_BN_CLICKED(IDC_GOALS, OnGoals) ON_CBN_SELCHANGE(IDC_SHIP_CLASS, OnSelchangeShipClass) ON_BN_CLICKED(IDC_INITIAL_STATUS, OnInitialStatus) ON_BN_CLICKED(IDC_WEAPONS, OnWeapons) ON_BN_CLICKED(IDC_SHIP_RESET, OnShipReset) ON_BN_CLICKED(IDC_DELETE_SHIP, OnDeleteShip) ON_BN_CLICKED(IDC_SHIP_TBL, OnShipTbl) ON_BN_CLICKED(IDC_NEXT, OnNext) ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree) ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree) ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues) ON_BN_CLICKED(IDC_PREV, OnPrev) ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation) ON_BN_CLICKED(IDC_PLAYER_SHIP, OnPlayerShip) ON_BN_CLICKED(IDC_NO_ARRIVAL_WARP, OnNoArrivalWarp) ON_BN_CLICKED(IDC_NO_DEPARTURE_WARP, OnNoDepartureWarp) ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation) ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey) ON_BN_CLICKED(IDC_FLAGS, OnFlags) ON_BN_CLICKED(IDC_IGNORE_ORDERS, OnIgnoreOrders) ON_BN_CLICKED(IDC_SPECIAL_EXP, OnSpecialExp) ON_BN_CLICKED(IDC_TEXTURES, OnTextures) ON_BN_CLICKED(IDC_SPECIAL_HITPOINTS, OnSpecialHitpoints) ON_BN_CLICKED(IDC_ALT_SHIP_CLASS, OnAltShipClass) ON_BN_CLICKED(IDC_RESTRICT_ARRIVAL, OnRestrictArrival) ON_BN_CLICKED(IDC_RESTRICT_DEPARTURE, OnRestrictDeparture) ON_WM_INITMENU() ON_BN_CLICKED(IDC_SET_AS_PLAYER_SHIP, OnSetAsPlayerShip) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CShipEditorDlg message handlers BOOL CShipEditorDlg::Create() { int i, index; BOOL r; CComboBox *ptr; r = CDialog::Create(IDD, Fred_main_wnd); ptr = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION); ptr->ResetContent(); for (i=0; iAddString(Arrival_location_names[i]); } ptr = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION); ptr->ResetContent(); for (i=0; iAddString(Departure_location_names[i]); } ptr = (CComboBox *) GetDlgItem(IDC_SHIP_CLASS); ptr->ResetContent(); for (i=0; iAddString(Ship_info[i].name); } ptr = (CComboBox *) GetDlgItem(IDC_AI_CLASS); ptr->ResetContent(); for (i=0; iAddString(Ai_class_names[i]); } // alternate ship name combobox ptr = (CComboBox *)GetDlgItem(IDC_SHIP_ALT); ptr->ResetContent(); ptr->AddString(""); ptr->SetCurSel(0); // deal with the persona dialog ptr = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA); ptr->ResetContent(); index = ptr->AddString(""); if ( index >= 0 ){ ptr->SetItemData(index, NO_PERSONA_INDEX); } for ( i = 0; i < Num_personas; i++ ) { if ( Personas[i].flags & PERSONA_FLAG_WINGMAN ) { int index; // don't bother putting any vasudan personas on the list -- done automatically by code // if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){ // continue; // } CString persona_name = Personas[i].name; if ( Personas[i].flags & PERSONA_FLAG_VASUDAN ){ persona_name += " -Vas"; } index = ptr->AddString(persona_name); if ( index >= 0 ){ ptr->SetItemData(index, i); } } } m_score.setup(IDC_SCORE, this); m_arrival_dist.setup(IDC_ARRIVAL_DISTANCE, this); m_arrival_delay.setup(IDC_ARRIVAL_DELAY, this); m_departure_delay.setup(IDC_DEPARTURE_DELAY, this); m_hotkey = 0; m_arrival_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX)); m_departure_tree.link_modified(&modified); m_departure_tree.setup(); m_arrival_delay_spin.SetRange(0, 999); m_departure_delay_spin.SetRange(0, 999); initialize_data(1); return r; } // This gets called when you click on the "X" button. Note that OnClose // does not destroy the window. It only hides it. void CShipEditorDlg::OnClose() { if (verify() && (!bypass_errors)) { SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); bypass_errors = 0; return; } if (update_data()) { SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); bypass_errors = 0; return; } SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } BOOL CShipEditorDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { BOOL r; r = CDialog::Create(IDD, pParentWnd); return r; } int CShipEditorDlg::tristate_set(int val, int cur_state) { if (val) { if (!cur_state){ return 2; } } else { if (cur_state){ return 2; } } return cur_state; } // called to initialize the dialog box to reflect what ships we currently have marked. Any // time what we have marked changes, this should get called again. // // Notes: player_count is the number of player starts marked, when we are in a non-multiplayer // mission (NMM). In a multiplayer mission (MM), player_count will always be zero. // ship_count in NMM is the number of ships (i.e. not player starts) that are marked. In MM, // ship_count is the number of ships and player starts. Total_count is the sum of ship_count // and player_count in all cases. The reason player_count isn't used in MM, and ship_count // is used instead to track player starts is because in MM, player starts can be edited as // freely as AI ships, and are very likely to be AI ships sometimes. Thus, treating them like // AI ships instead of player starts simplifies processing. // void CShipEditorDlg::initialize_data(int full_update) { int i, type, ship_count, player_count, total_count, wing = -1, pvalid_count; int a_cue, d_cue, cue_init = 0, cargo = 0, base_ship, base_player, pship = -1; int no_arrival_warp = 0, no_departure_warp = 0, escort_count, ship_orders, current_orders; int pship_count; // a total count of the player ships not marked object *objp; CWnd *w = NULL; CString str; CComboBox *box; CSingleLock sync(&CS_update); nprintf(("Fred routing", "Ship dialog load\n")); if (!GetSafeHwnd() || bypass_all) return; sync.Lock(); // don't initialize if we are still updating. Wait until update is done. box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET); management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS ); box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET); management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); if (The_mission.game_type & MISSION_TYPE_MULTI){ mission_type = 0; // multi player mission } else { mission_type = 1; // non-multiplayer mission (implies single player mission I guess) } // figure out what all we are editing. ship_count = player_count = escort_count = pship_count = pvalid_count = 0; base_ship = base_player = -1; enable = p_enable = 1; objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if ((objp->type == OBJ_SHIP) && (Ships[objp->instance].flags & SF_ESCORT)){ escort_count++; // get a total count of escort ships } if (objp->type == OBJ_START){ pship_count++; // count all player starts in mission } if (objp->flags & OF_MARKED) { type = objp->type; if ((type == OBJ_START) && !mission_type){ // in multiplayer missions, starts act like ships type = OBJ_SHIP; } i = -1; if (type == OBJ_START) { player_count++; // if player_count is 1, base_player will be the one and only player i = base_player = objp->instance; } else if (type == OBJ_SHIP) { ship_count++; // if ship_count is 1, base_ship will be the one and only ship i = base_ship = objp->instance; } if (i >= 0){ if (Ship_info[Ships[i].ship_info_index].flags & SIF_PLAYER_SHIP){ pvalid_count++; } } } objp = GET_NEXT(objp); } total_count = ship_count + player_count; // get total number of objects being edited. if (total_count > 1){ multi_edit = 1; } else { multi_edit = 0; } a_cue = d_cue = -1; m_arrival_location = -1; m_arrival_dist.blank(); m_arrival_target = -1; m_arrival_delay.blank(); m_departure_location = -1; m_departure_target = -1; m_departure_delay.blank(); player_ship = single_ship = -1; m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node; select_sexp_node = -1; ship_orders = 0; // assume they are all the same type if (ship_count) { box = (CComboBox *) GetDlgItem(IDC_SHIP_CARGO1); box->ResetContent(); for (i=0; iAddString(Cargo_names[i]); } if (!multi_edit) { Assert((ship_count == 1) && (base_ship >= 0)); m_ship_name = Ships[base_ship].ship_name; } else { m_ship_name = _T(""); } m_update_arrival = m_update_departure = 1; base_player = 0; objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) { if (objp->flags & OF_MARKED) { // do processing for both ships and players i = get_ship_from_obj(objp); if (base_player >= 0) { m_ship_class = Ships[i].ship_info_index; m_team = Ships[i].team; pship = (objp->type == OBJ_START) ? 1 : 0; base_player = -1; } else { if (Ships[i].ship_info_index != m_ship_class) m_ship_class = -1; if (Ships[i].team != m_team) m_team = -1; pship = tristate_set(Objects[Ships[i].objnum].type == OBJ_START, pship); } // 'and' in the ship type of this ship to our running bitfield current_orders = ship_get_default_orders_accepted( &Ship_info[Ships[i].ship_info_index] ); if (!ship_orders){ ship_orders = current_orders; } else if (ship_orders != current_orders){ ship_orders = -1; } if (Ships[i].flags & SF_ESCORT){ escort_count--; // remove marked escorts from count } if (Objects[Ships[i].objnum].type == OBJ_START){ pship_count--; // removed marked starts from count } // do processing only for ships (plus players if in a multiplayer mission if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) { // process this if ship not in a wing if (Ships[i].wingnum < 0) { if (!cue_init) { cue_init = 1; a_cue = Ships[i].arrival_cue; d_cue = Ships[i].departure_cue; m_arrival_location = Ships[i].arrival_location; m_arrival_dist.init(Ships[i].arrival_distance); m_arrival_target = Ships[i].arrival_anchor; m_arrival_delay.init(Ships[i].arrival_delay); m_departure_location = Ships[i].departure_location; m_departure_delay.init(Ships[i].departure_delay); m_departure_target = Ships[i].departure_anchor; } else { cue_init++; if (Ships[i].arrival_location != m_arrival_location){ m_arrival_location = -1; } if (Ships[i].departure_location != m_departure_location){ m_departure_location = -1; } m_arrival_dist.set(Ships[i].arrival_distance); m_arrival_delay.set(Ships[i].arrival_delay); m_departure_delay.set(Ships[i].departure_delay); if (Ships[i].arrival_anchor != m_arrival_target){ m_arrival_target = -1; } if (!cmp_sexp_chains(a_cue, Ships[i].arrival_cue)) { a_cue = -1; m_update_arrival = 0; } if (!cmp_sexp_chains(d_cue, Ships[i].departure_cue)) { d_cue = -1; m_update_departure = 0; } if ( Ships[i].departure_anchor != m_departure_target ){ m_departure_target = -1; } } } // process the first ship in group, else process the rest if (base_ship >= 0) { m_ai_class = Ships[i].weapons.ai_class; cargo = Ships[i].cargo1; m_cargo1 = Cargo_names[cargo]; m_hotkey = Ships[i].hotkey + 1; m_score.init(Ships[i].score); m_persona = Ships[i].persona_index + 1; // we use final_death_time member of ship structure for holding the amount of time before a mission // to destroy this ship wing = Ships[i].wingnum; if (wing < 0) { GetDlgItem(IDC_WING) -> SetWindowText("None"); } else { GetDlgItem(IDC_WING) -> SetWindowText(Wings[wing].name); if (!query_whole_wing_marked(wing)) m_update_arrival = m_update_departure = 0; } // set routine local varaiables for ship/object flags no_arrival_warp = (Ships[i].flags & SF_NO_ARRIVAL_WARP) ? 1 : 0; no_departure_warp = (Ships[i].flags & SF_NO_DEPARTURE_WARP) ? 1 : 0; base_ship = -1; if (!multi_edit) single_ship = i; } else { if (Ships[i].weapons.ai_class != m_ai_class){ m_ai_class = -1; } if (Ships[i].cargo1 != cargo){ m_cargo1 = _T(""); } m_score.set(Ships[i].score); if (Ships[i].hotkey != m_hotkey - 1){ m_hotkey = -1; } if ( Ships[i].persona_index != (m_persona-1) ){ m_persona = -1; } if (Ships[i].wingnum != wing){ GetDlgItem(IDC_WING) -> SetWindowText(""); } no_arrival_warp = tristate_set(Ships[i].flags & SF_NO_ARRIVAL_WARP, no_arrival_warp); no_departure_warp = tristate_set(Ships[i].flags & SF_NO_DEPARTURE_WARP, no_departure_warp); } } } } objp = GET_NEXT(objp); } if (multi_edit) { m_arrival_tree.clear_tree(""); m_departure_tree.clear_tree(""); } if (cue_init) { m_arrival_tree.load_tree(a_cue); m_departure_tree.load_tree(d_cue, "false"); } else { m_arrival_tree.clear_tree(); m_arrival_tree.DeleteAllItems(); m_departure_tree.clear_tree(); m_departure_tree.DeleteAllItems(); } m_player_ship.SetCheck(pship); m_no_arrival_warp.SetCheck(no_arrival_warp); m_no_departure_warp.SetCheck(no_departure_warp); if (!multi_edit) { i = m_arrival_tree.select_sexp_node; if (i != -1) { w = GetDlgItem(IDC_ARRIVAL_TREE); m_arrival_tree.hilite_item(i); } else { i = m_departure_tree.select_sexp_node; if (i != -1) { w = GetDlgItem(IDC_DEPARTURE_TREE); m_departure_tree.hilite_item(i); } } } } else { // no ships selected, 0 or more player ships selected if (player_count > 1) { // multiple player ships selected Assert(base_player >= 0); m_ship_name = _T(""); m_player_ship.SetCheck(TRUE); objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if ((objp->type == OBJ_START) && (objp->flags & OF_MARKED)) { i = objp->instance; if (base_player >= 0) { m_ship_class = Ships[i].ship_info_index; m_team = Ships[i].team; base_player = -1; } else { if (Ships[i].ship_info_index != m_ship_class) m_ship_class = -1; if (Ships[i].team != m_team) m_team = -1; } } objp = GET_NEXT(objp); } // only 1 player selected.. } else if (query_valid_object() && (Objects[cur_object_index].type == OBJ_START)) { Assert((player_count == 1) && !multi_edit); player_ship = Objects[cur_object_index].instance; m_ship_name = Ships[player_ship].ship_name; m_ship_class = Ships[player_ship].ship_info_index; m_team = Ships[player_ship].team; m_player_ship.SetCheck(TRUE); } else { // no ships or players selected.. m_ship_name = _T(""); m_ship_class = -1; m_team = -1; m_persona = -1; m_player_ship.SetCheck(FALSE); } m_ai_class = -1; m_cargo1 = _T(""); m_hotkey = 0; m_score.blank(); // cause control to be blank m_arrival_location = -1; m_departure_location = -1; m_arrival_delay.blank(); m_departure_delay.blank(); m_arrival_dist.blank(); m_arrival_target = -1; m_departure_target = -1; m_arrival_tree.clear_tree(); m_arrival_tree.DeleteAllItems(); m_departure_tree.clear_tree(); m_departure_tree.DeleteAllItems(); m_no_arrival_warp.SetCheck(0); m_no_departure_warp.SetCheck(0); enable = p_enable = 0; GetDlgItem(IDC_WING)->SetWindowText(_T("None")); } box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET); // must put the appropriate ships into the list depending on arrival location if ( m_arrival_location != ARRIVE_FROM_DOCK_BAY ){ management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS ); } else { management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } // set the internal variable appropriatly // Goober5000 - gah, this is ridiculous! Prior to this point in the function (and only in this function), // m_arrival_target seems to refer to the arrival anchor. The rest of the time, it refers to the index // of the drop-down list. if (m_arrival_target >= 0) { if (m_arrival_target & SPECIAL_ARRIVAL_ANCHOR_FLAG) { // figure out what the box represents this as char tmp[NAME_LENGTH + 15]; stuff_special_arrival_anchor_name(tmp, m_arrival_target, 0); // find it in the box m_arrival_target = box->FindStringExact(-1, tmp); } else { // find it in the box m_arrival_target = box->FindStringExact(-1, Ships[m_arrival_target].ship_name); } } box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET); // must put the appropriate ships into the list depending on departure location if ( m_departure_location == DEPART_AT_DOCK_BAY ){ management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { box->ResetContent(); } if ( m_departure_target >= 0 ){ m_departure_target = box->FindStringExact( -1, Ships[m_departure_target].ship_name ); } initialized = 1; if (player_count) { box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM); if (!mission_type){ // multiplayer mission box->EnableWindow(TRUE); } else { box->EnableWindow(FALSE); m_team = -1; } box->ResetContent(); for (i=0; iAddString(Iff_info[i].iff_name); } else { box = (CComboBox *) GetDlgItem(IDC_SHIP_TEAM); box->EnableWindow(enable); box->ResetContent(); for (i=0; iAddString(Iff_info[i].iff_name); } } m_score.display(); m_arrival_dist.display(); m_arrival_delay.display(); m_departure_delay.display(); if (full_update) UpdateData(FALSE); if (!cue_init) { GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(FALSE); GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(FALSE); GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE); GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(FALSE); GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(FALSE); GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(FALSE); GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(FALSE); GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(FALSE); GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(FALSE); GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(FALSE); } else { GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable); if (m_arrival_location) { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable); } else { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE); } if (m_arrival_location == ARRIVE_FROM_DOCK_BAY) { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(enable); } else { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(FALSE); } GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable); if ( m_departure_location ) { GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable); } else { GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE); } if (m_departure_location == DEPART_AT_DOCK_BAY) { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(enable); } else { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(FALSE); } GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable); GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable); GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable); } if (total_count) { GetDlgItem(IDC_SHIP_NAME)->EnableWindow(!multi_edit); GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(TRUE); GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE); GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(TRUE); GetDlgItem(IDC_WEAPONS)->EnableWindow(m_ship_class >= 0); GetDlgItem(IDC_FLAGS)->EnableWindow(TRUE); GetDlgItem(IDC_TEXTURES)->EnableWindow(TRUE); GetDlgItem(IDC_ALT_SHIP_CLASS)->EnableWindow(TRUE); GetDlgItem(IDC_SPECIAL_EXP)->EnableWindow(TRUE); GetDlgItem(IDC_SPECIAL_HITPOINTS)->EnableWindow(TRUE); } else { GetDlgItem(IDC_SHIP_NAME)->EnableWindow(FALSE); GetDlgItem(IDC_SHIP_CLASS)->EnableWindow(FALSE); GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE); GetDlgItem(IDC_INITIAL_STATUS)->EnableWindow(FALSE); GetDlgItem(IDC_WEAPONS)->EnableWindow(FALSE); GetDlgItem(IDC_FLAGS)->EnableWindow(FALSE); GetDlgItem(IDC_TEXTURES)->EnableWindow(FALSE); GetDlgItem(IDC_ALT_SHIP_CLASS)->EnableWindow(FALSE); GetDlgItem(IDC_SPECIAL_EXP)->EnableWindow(FALSE); GetDlgItem(IDC_SPECIAL_HITPOINTS)->EnableWindow(FALSE); } // disable textures for multiple ships if (multi_edit) { GetDlgItem(IDC_TEXTURES)->EnableWindow(FALSE); } GetDlgItem(IDC_AI_CLASS)->EnableWindow(enable); GetDlgItem(IDC_SHIP_CARGO1)->EnableWindow(enable); GetDlgItem(IDC_HOTKEY)->EnableWindow(enable); if ((m_ship_class >= 0) && !(Ship_info[m_ship_class].flags & SIF_CARGO) && !(Ship_info[m_ship_class].flags & SIF_NO_SHIP_TYPE)) GetDlgItem(IDC_GOALS)->EnableWindow(enable); else if (multi_edit) GetDlgItem(IDC_GOALS)->EnableWindow(enable); else GetDlgItem(IDC_GOALS)->EnableWindow(FALSE); // !pship_count used because if allowed to clear, we would have no player starts // mission_type 0 = multi, 1 = single if (mission_type || !pship_count || (pship_count + total_count > MAX_PLAYERS) || (pvalid_count < total_count)) m_player_ship.EnableWindow(FALSE); else m_player_ship.EnableWindow(TRUE); // show the "set player" button only if single player if (mission_type) GetDlgItem(IDC_SET_AS_PLAYER_SHIP)->ShowWindow(TRUE); else GetDlgItem(IDC_SET_AS_PLAYER_SHIP)->ShowWindow(FALSE); // enable the "set player" button only if single player, single edit, and ship is in player wing { int marked_ship = (player_ship >= 0) ? player_ship : single_ship; if (mission_type && total_count && !multi_edit && wing_is_player_wing(Ships[marked_ship].wingnum)) GetDlgItem(IDC_SET_AS_PLAYER_SHIP)->EnableWindow(TRUE); else GetDlgItem(IDC_SET_AS_PLAYER_SHIP)->EnableWindow(FALSE); } GetDlgItem(IDC_DELETE_SHIP)->EnableWindow(enable); GetDlgItem(IDC_SHIP_RESET)->EnableWindow(enable); GetDlgItem(IDC_SCORE)->EnableWindow(enable); //#ifndef NDEBUG GetDlgItem(IDC_SHIP_TBL)->EnableWindow(m_ship_class >= 0); //#else // GetDlgItem(IDC_SHIP_TBL)->EnableWindow(0); // GetDlgItem(IDC_SHIP_TBL)->ShowWindow(SW_HIDE); //#endif if (cue_init > 1) { // more than one ship (players don't have cues to edit) GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_SHOW); GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_SHOW); } else { GetDlgItem(IDC_UPDATE_ARRIVAL)->ShowWindow(SW_HIDE); GetDlgItem(IDC_UPDATE_DEPARTURE)->ShowWindow(SW_HIDE); } if (multi_edit || (total_count > 1)) { // we will allow the ignore orders dialog to be multi edit if all selected // ships are the same type. the ship_type (local) variable holds the ship types // for all ships. Determine how may bits set and enable/diable window // as appropriate if ( /*(m_team == -1) ||*/ (ship_orders == -1) ){ GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(FALSE); } else { GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(TRUE); } } else // always enabled when one ship is selected GetDlgItem(IDC_IGNORE_ORDERS)->EnableWindow(enable); // always enabled if >= 1 ship selected GetDlgItem(IDC_SHIP_PERSONA)->EnableWindow(enable); if (multi_edit){ SetWindowText("Edit Marked Ships"); } else if (player_count) { SetWindowText("Edit Player Ship"); } else { SetWindowText("Edit Ship"); } // setup alternate name stuff if(player_ship >= 0){ ship_alt_name_init(player_ship); } else { ship_alt_name_init(single_ship); } modified = 0; if (w){ w->SetFocus(); } } // update ship structure(s) with dialog data. The data is first checked for errors. If // no errors occur, returns 0. If an error occurs, returns -1. If the update is bypassed, // returns 1. Bypass is necessary to avoid an infinite loop, and it doesn't actually // update the data. Bypass only occurs if bypass mode is active and we still get an error. // Once the error no longer occurs, bypass mode is cleared and data is updated. int CShipEditorDlg::update_data(int redraw) { char *str, old_name[255]; object *ptr; int i, z, wing; CSingleLock sync(&CS_cur_object_index), sync2(&CS_update); nprintf(("Fred routing", "Ship dialog save\n")); if (!GetSafeHwnd() || !initialized || bypass_all) return 0; sync.Lock(); // don't allow cur_object_index to change while we are using it sync2.Lock(); // don't allow reinitialization until we are done updating UpdateData(TRUE); UpdateData(TRUE); Wing_editor_dialog.update_data_safe(); if (multi_edit) { // editing multiple ships (ships and/or players) ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags & OF_MARKED)) update_ship(get_ship_from_obj(ptr)); ptr = GET_NEXT(ptr); } } else if (player_ship >= 0) { // editing a single player update_ship(player_ship); } else if (single_ship >= 0) { // editing a single ship ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (cur_object_index != OBJ_INDEX(ptr))) { str = Ships[ptr->instance].ship_name; if (!stricmp(m_ship_name, str)) { if (bypass_errors) return 1; bypass_errors = 1; z = MessageBox("This ship name is already being used by another ship\n" "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL); if (z == IDCANCEL) return -1; m_ship_name = _T(Ships[single_ship].ship_name); UpdateData(FALSE); } } ptr = GET_NEXT(ptr); } for (i=0; i= 0) { Assert((wing < MAX_WINGS) && Wings[wing].wave_count); for (i=0; itype == OBJ_START) { Player_start_shipnum = ptr->instance; break; } ptr = GET_NEXT(ptr); } } if (modified) set_modified(); Wing_editor_dialog.initialize_data_safe(1); bypass_errors = 0; modified = 0; if (redraw) update_map_window(); return 0; } int CShipEditorDlg::update_ship(int ship) { int z, d; CString str; CComboBox *box; int persona; // THIS DIALOG IS THE SOME OF THE WORST CODE I HAVE EVER SEEN IN MY ENTIRE LIFE. // IT TOOK A RIDICULOUSLY LONG AMOUNT OF TIME TO ADD 2 FUNCTIONS. OMG ship_alt_name_close(ship); if ((Ships[ship].ship_info_index != m_ship_class) && (m_ship_class != -1)) { change_ship_type(ship, m_ship_class); set_modified(); m_score.init(Ships[ship].score); m_score.display(); } if (m_team != -1) MODIFY(Ships[ship].team, m_team); if (Objects[Ships[ship].objnum].type != OBJ_SHIP){ if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)){ return 0; } } if (m_ai_class != -1){ MODIFY(Ships[ship].weapons.ai_class, m_ai_class); } if (strlen(m_cargo1)) { z = string_lookup(m_cargo1, Cargo_names, Num_cargo); if (z == -1) { Assert(Num_cargo < MAX_CARGO); z = Num_cargo++; strcpy(Cargo_names[z], m_cargo1); } MODIFY(Ships[ship].cargo1, (char)z); } m_score.save(&Ships[ship].score); if (m_arrival_location != -1) MODIFY(Ships[ship].arrival_location, m_arrival_location); if (m_departure_location != -1) MODIFY(Ships[ship].departure_location, m_departure_location); if (m_persona != -1) { // do the persona update // m_persona holds the index into the list. Get the item data associated with this index and then // assign to the ship taking care that we check for the NO_PERSONA_INDEX id box = (CComboBox *)GetDlgItem(IDC_SHIP_PERSONA); persona = box->GetItemData(m_persona); if ( persona == NO_PERSONA_INDEX ) persona = -1; MODIFY(Ships[ship].persona_index, persona); } if (Ships[ship].wingnum < 0) { if (!multi_edit || m_update_arrival) { // should we update the arrival cue? if (Ships[ship].arrival_cue >= 0) free_sexp2(Ships[ship].arrival_cue); Ships[ship].arrival_cue = m_arrival_tree.save_tree(); } if (!multi_edit || m_update_departure) { if (Ships[ship].departure_cue >= 0) free_sexp2(Ships[ship].departure_cue); Ships[ship].departure_cue = m_departure_tree.save_tree(); } m_arrival_dist.save(&Ships[ship].arrival_distance); m_arrival_delay.save(&Ships[ship].arrival_delay); m_departure_delay.save(&Ships[ship].departure_delay); if (m_arrival_target >= 0) { z = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target); MODIFY(Ships[ship].arrival_anchor, z); // if the arrival is not hyperspace or docking bay -- force arrival distance to be // greater than 2*radius of target. if (((m_arrival_location != ARRIVE_FROM_DOCK_BAY) && (m_arrival_location != ARRIVE_AT_LOCATION)) && (z >= 0) && !(z & SPECIAL_ARRIVAL_ANCHOR_FLAG)) { d = int(min(500, 2.0f * Objects[Ships[ship].objnum].radius)); if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) { str.Format("Ship must arrive at least %d meters away from target.\n" "Value has been reset to this. Use with caution!\r\n" "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[ship].objnum].radius) ); MessageBox(str); if (Ships[ship].arrival_distance < 0) Ships[ship].arrival_distance = -d; else Ships[ship].arrival_distance = d; m_arrival_dist.fix(Ships[ship].arrival_distance); } } } z = ((CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target); MODIFY(Ships[ship].departure_anchor, z ); } if (m_hotkey != -1) MODIFY(Ships[ship].hotkey, m_hotkey - 1); switch( m_no_arrival_warp.GetCheck() ) { case 0: if (Ships[ship].flags & SF_NO_ARRIVAL_WARP) set_modified(); Ships[ship].flags &= ~SF_NO_ARRIVAL_WARP; break; case 1: if (!(Ships[ship].flags & SF_NO_ARRIVAL_WARP)) set_modified(); Ships[ship].flags |= SF_NO_ARRIVAL_WARP; break; } switch( m_no_departure_warp.GetCheck() ) { case 0: if (Ships[ship].flags & SF_NO_DEPARTURE_WARP) set_modified(); Ships[ship].flags &= ~SF_NO_DEPARTURE_WARP; break; case 1: if (!(Ships[ship].flags & SF_NO_DEPARTURE_WARP)) set_modified(); Ships[ship].flags |= SF_NO_DEPARTURE_WARP; break; } switch (m_player_ship.GetCheck()) { case 1: if (Objects[Ships[ship].objnum].type != OBJ_START) { Player_starts++; set_modified(); } Objects[Ships[ship].objnum].type = OBJ_START; break; case 0: if (Objects[Ships[ship].objnum].type == OBJ_START) { Player_starts--; set_modified(); } Objects[Ships[ship].objnum].type = OBJ_SHIP; break; } Update_ship = 1; return 0; } void CShipEditorDlg::OnOK() { HWND h; CWnd *w; w = GetFocus(); if (w) { h = w->m_hWnd; GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus(); ::SetFocus(h); } } void CShipEditorDlg::OnInitMenu(CMenu *pMenu) { CMenu *m; m = pMenu->GetSubMenu(0); clear_menu(m); generate_ship_popup_menu(m, ID_SHIP_MENU, MF_ENABLED, SHIP_FILTER_PLAYERS); if (cur_ship != -1) m->CheckMenuItem(ID_SHIP_MENU + cur_ship, MF_BYCOMMAND | MF_CHECKED); CWnd::OnInitMenu(pMenu); } BOOL CShipEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam) { int id, ship; id = LOWORD(wParam); if (id >= ID_SHIP_MENU && id < ID_SHIP_MENU + MAX_SHIPS) { if (!update_data()) { ship = id - ID_SHIP_MENU; unmark_all(); set_cur_object_index(Ships[ship].objnum); return 1; } } return CDialog::OnCommand(wParam, lParam); } void CShipEditorDlg::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { m_arrival_tree.right_clicked(); *pResult = 0; } void CShipEditorDlg::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { m_departure_tree.right_clicked(); *pResult = 0; } void CShipEditorDlg::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) { *pResult = 0; modified = editing = 1; } else *pResult = 1; } void CShipEditorDlg::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) { *pResult = 0; modified = editing = 1; } else *pResult = 1; } void CShipEditorDlg::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText); editing = 0; } void CShipEditorDlg::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText); editing = 0; } int CShipEditorDlg::verify() { nprintf(("Fred routing", "Ship dialog verify\n")); if (!GetSafeHwnd() || !modified) return 0; if (bypass_errors) return 1; return 0; } void CShipEditorDlg::OnGoals() { ShipGoalsDlg dlg_goals; Assert(query_valid_object()); // if (multi_edit) // dlg_goals.initialize_multi(); // // else { // Assert(single_ship != -1); // dlg_goals.self_ship = single_ship; // dlg_goals.initialize(Ai_info[Ships[single_ship].ai_index].goals); // } if (!multi_edit) { Assert(single_ship != -1); dlg_goals.self_ship = single_ship; } dlg_goals.DoModal(); if (!multi_edit && !query_initial_orders_empty(Ai_info[Ships[single_ship].ai_index].goals)) if ((Ships[single_ship].wingnum >= 0) && (query_initial_orders_conflict(Ships[single_ship].wingnum))) MessageBox("This ship's wing also has initial orders", "Possible conflict"); } void CShipEditorDlg::OnSelchangeShipClass() { object *ptr; UpdateData(TRUE); UpdateData(TRUE); ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags & OF_MARKED)) if (Ships[ptr->instance].ship_info_index != m_ship_class) { change_ship_type(ptr->instance, m_ship_class); set_modified(); m_score.init(Ships[ptr->instance].score); m_score.display(); } ptr = GET_NEXT(ptr); } update_map_window(); } void CShipEditorDlg::OnInitialStatus() { initial_status dlg; dlg.m_multi_edit = multi_edit; dlg.DoModal(); } void CShipEditorDlg::OnWeapons() { int i, ship = -1; WeaponEditorDlg dlg; object *objp; CComboBox *box; dlg.m_multi_edit = multi_edit; dlg.DoModal(); if (multi_edit) { objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->flags & OF_MARKED) if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) { i = objp->instance; if (ship) { if (Ships[i].weapons.ai_class != Ships[ship].weapons.ai_class) m_ai_class = -1; } else { ship = i; m_ai_class = Ships[i].weapons.ai_class; } } objp = GET_NEXT(objp); } } else { ship = single_ship; if (ship < 0) ship = player_ship; Assert(ship >= 0); m_ai_class = Ships[ship].weapons.ai_class; } box = (CComboBox *) GetDlgItem(IDC_AI_CLASS); box->SetCurSel(m_ai_class); } void CShipEditorDlg::OnShipReset() { int i, j, index, ship; object *objp; ship_info *sip; ship_subsys *ptr; ship_weapon *wp; model_subsystem *sp; m_cargo1 = "Nothing"; m_ai_class = AI_DEFAULT_CLASS; if (m_ship_class) { m_team = Species_info[Ship_info[m_ship_class].species].default_iff; } objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (((objp->type == OBJ_SHIP) || ((objp->type == OBJ_START) && !mission_type)) && (objp->flags & OF_MARKED)) { ship = objp->instance; // reset ship goals for (i=0; iphys_info.speed = 0.0f; shield_set_strength(objp, 100.0f); objp->hull_strength = 100.0f; sip = &Ship_info[Ships[ship].ship_info_index]; for (i=0; inum_primary_banks; i++) Ships[ship].weapons.primary_bank_weapons[i] = sip->primary_bank_weapons[i]; for (i=0; inum_secondary_banks; i++) { Ships[ship].weapons.secondary_bank_weapons[i] = sip->secondary_bank_weapons[i]; Ships[ship].weapons.secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i]; } index = 0; ptr = GET_FIRST(&Ships[ship].subsys_list); while (ptr != END_OF_LIST(&Ships[ship].subsys_list)) { ptr->current_hits = 0.0f; if (ptr->system_info->type == SUBSYSTEM_TURRET) { wp = &ptr->weapons; sp = &Ship_info[Ships[ship].ship_info_index].subsystems[index]; j = 0; for (i=0; iprimary_banks[i] != -1){ wp->primary_bank_weapons[j++] = sp->primary_banks[i]; } } wp->num_primary_banks = j; j = 0; for (i=0; isecondary_banks[i] != -1) { wp->secondary_bank_weapons[j] = sp->secondary_banks[i]; wp->secondary_bank_capacity[j++] = sp->secondary_bank_capacity[i]; } } wp->num_secondary_banks = j; for (i=0; isecondary_bank_ammo[i] = 100; } } index++; ptr = GET_NEXT(ptr); } } objp = GET_NEXT(objp); } UpdateData(FALSE); if (multi_edit){ MessageBox("Ships reset to ship class defaults"); } else { MessageBox("Ship reset to ship class defaults"); } } void CShipEditorDlg::OnDeleteShip() { delete_marked(); unmark_all(); } void CShipEditorDlg::OnShipTbl() { text_view_dlg dlg; dlg.set(m_ship_class); dlg.DoModal(); } int CShipEditorDlg::make_ship_list(int *arr) { int n = 0; object *ptr; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)){ arr[n++] = OBJ_INDEX(ptr); } ptr = GET_NEXT(ptr); } return n; } void CShipEditorDlg::OnPrev() { int i, n, arr[MAX_SHIPS]; if (!update_data()) { n = make_ship_list(arr); if (!n){ return; } if (cur_ship < 0){ i = n - 1; } else { for (i=0; iitemNew.hItem; if (h){ m_arrival_tree.update_help(h); } *pResult = 0; } void CShipEditorDlg::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { HTREEITEM h; NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; h = pNMTreeView->itemNew.hItem; if (h){ m_departure_tree.update_help(h); } *pResult = 0; } void CShipEditorDlg::calc_cue_height() { CRect cue, help; GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue); cue_height = (cue.bottom - cue.top)+20; if (Show_sexp_help){ GetDlgItem(IDC_HELP_BOX)->GetWindowRect(help); cue_height += (help.bottom - help.top); } if (Hide_ship_cues) { ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1); OnHideCues(); } } void CShipEditorDlg::show_hide_sexp_help() { CRect rect, help; GetDlgItem(IDC_HELP_BOX)->GetWindowRect(help); long box_size = (help.bottom - help.top); if (Show_sexp_help){ cue_height += box_size; } else { cue_height -= box_size; } if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()){ return; } GetWindowRect(rect); if (Show_sexp_help){ rect.bottom += box_size; } else { rect.bottom -= box_size; } MoveWindow(rect); } void CShipEditorDlg::OnHideCues() { CRect rect; GetWindowRect(rect); if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) { rect.bottom -= cue_height; Hide_ship_cues = 1; } else { rect.bottom += cue_height; Hide_ship_cues = 0; } MoveWindow(rect); } void CShipEditorDlg::OnSelchangeArrivalLocation() { CComboBox *box; UpdateData(); box = (CComboBox *)GetDlgItem( IDC_ARRIVAL_TARGET ); if (m_arrival_location) { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE); if (m_arrival_target < 0) { m_arrival_target = 0; } // determine which items we should put into the arrival target combo box if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) { management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS ); } } else { m_arrival_target = -1; GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE); } if (m_arrival_location == ARRIVE_FROM_DOCK_BAY) { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(TRUE); } else { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(FALSE); } UpdateData(FALSE); } void CShipEditorDlg::OnSelchangeDepartureLocation() { CComboBox *box; UpdateData(); box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET); if ( m_departure_location ) { box->EnableWindow(TRUE); if ( m_departure_target < 0 ) { m_departure_target = 0; } // we need to build up the list box content based on the departure type. When // from a docking bay, only show ships in the list which have them. Show all ships otherwise if ( m_departure_location == DEPART_AT_DOCK_BAY ) { management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { // I think that this section is currently illegal Int3(); } } else { m_departure_target = -1; box->EnableWindow(FALSE); } if (m_departure_location == DEPART_AT_DOCK_BAY) { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(TRUE); } else { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(FALSE); } UpdateData(FALSE); } void CShipEditorDlg::OnPlayerShip() { if (m_player_ship.GetCheck() == 1) m_player_ship.SetCheck(0); else m_player_ship.SetCheck(1); update_map_window(); } void CShipEditorDlg::OnNoArrivalWarp() { if (m_no_arrival_warp.GetCheck() == 1) m_no_arrival_warp.SetCheck(0); else m_no_arrival_warp.SetCheck(1); } void CShipEditorDlg::OnNoDepartureWarp() { if (m_no_departure_warp.GetCheck() == 1) m_no_departure_warp.SetCheck(0); else m_no_departure_warp.SetCheck(1); } // function to possibly warn user when he selects a hotkey which might be used for // a player wing. void CShipEditorDlg::OnSelchangeHotkey() { int set_num; char buf[256]; UpdateData(TRUE); set_num = m_hotkey-1; // use -1 since values associated with hotkey sets are 1 index based // the first three sets are generally reserved for player starting wings. if ( set_num < MAX_STARTING_WINGS ) { sprintf( buf, "This hotkey set should probably be reserved\nfor wing %s", Starting_wing_names[set_num] ); MessageBox(buf, NULL, MB_OK); } } void CShipEditorDlg::OnFlags() { ship_flags_dlg dlg; dlg.setup(p_enable); dlg.DoModal(); } void CShipEditorDlg::OnIgnoreOrders() { // TODO: Add your control notification handler code here ignore_orders_dlg player_order_dlg; Assert(query_valid_object()); if (!multi_edit) { if ( single_ship != -1 ){ player_order_dlg.m_ship = single_ship; } else { player_order_dlg.m_ship = player_ship; } } else { player_order_dlg.m_ship = -1; } player_order_dlg.DoModal(); } void CShipEditorDlg::OnSpecialExp() { // TODO: Add your control notification handler code here ShipSpecialDamage dlg; dlg.DoModal(); } // alternate ship name stuff void CShipEditorDlg::ship_alt_name_init(int base_ship) { int idx; CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT); if(ptr == NULL){ Int3(); return; } // multi-edit. bah if(multi_edit){ GetDlgItem(IDC_SHIP_ALT)->EnableWindow(FALSE); return; } GetDlgItem(IDC_SHIP_ALT)->EnableWindow(TRUE); // reset the combobox and add all relevant strings ptr->ResetContent(); ptr->AddString(""); for(idx=0; idxAddString(Mission_alt_types[idx]); } // "none" if(base_ship < 0){ ptr->SetCurSel(0); } // otherwise look his stuff up if(strlen(Fred_alt_names[base_ship])){ ptr->SelectString(0, Fred_alt_names[base_ship]); } else { ptr->SetCurSel(0); } } void CShipEditorDlg::ship_alt_name_close(int base_ship) { CString cstr; char str[NAME_LENGTH+2] = ""; char *p; CComboBox *ptr = (CComboBox*)GetDlgItem(IDC_SHIP_ALT); if(multi_edit){ return; } if(ptr == NULL){ Int3(); return; } // see if we have something besides "none" selected ptr->GetWindowText(cstr); if(cstr == CString("")){ // zero the entry strcpy(Fred_alt_names[base_ship], ""); return; } p = cstr.GetBuffer(0); if(p == NULL){ return; } strcpy(str, p); // otherwise see if it already exists if(mission_parse_lookup_alt(str) >= 0){ strcpy(Fred_alt_names[base_ship], str); return; } // otherwise try and add it if(mission_parse_add_alt(str) >= 0){ strcpy(Fred_alt_names[base_ship], str); return; } // bad - couldn't add strcpy(Fred_alt_names[base_ship], ""); MessageBox("Couldn't add new alternate type name. Already using too many!"); } void CShipEditorDlg::OnTextures() { CShipTexturesDlg dlg_textures; Assert(query_valid_object()); if (multi_edit) { MessageBox("Sorry, you can only edit textures for one ship at a time.", "Too many ships selected"); return; } // get the ship that's marked int marked_ship = (player_ship >= 0) ? player_ship : single_ship; dlg_textures.self_ship = marked_ship; dlg_textures.DoModal(); } void CShipEditorDlg::OnSpecialHitpoints() { ShipSpecialHitpoints dlg; dlg.DoModal(); } void CShipEditorDlg::OnAltShipClass() { AltShipClassDlg dlg; dlg.DoModal(); } // Goober5000 void CShipEditorDlg::OnSetAsPlayerShip() { Assert(query_valid_object()); if (multi_edit) { MessageBox("Please select only one ship.", "Too many ships selected"); return; } // since this is single player, clear all player ships and set only this one object *objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) { if (objp->flags & OF_MARKED) // there should only be one selected ship { // set as player ship objp->type = OBJ_START; objp->flags |= OF_PLAYER_SHIP; } else { // set as regular ship objp->type = OBJ_SHIP; objp->flags &= ~OF_PLAYER_SHIP; } } objp = GET_NEXT(objp); } // finally set editor dialog m_player_ship.SetCheck(1); update_map_window(); } // Goober5000 void CShipEditorDlg::OnRestrictArrival() { int arrive_from_ship; CComboBox *box; restrict_paths dlg; // grab stuff from GUI UpdateData(TRUE); if (m_arrival_location != ARRIVE_FROM_DOCK_BAY) { Int3(); return; } box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET); if (box->GetCount() == 0) return; arrive_from_ship = box->GetItemData(m_arrival_target); if (!ship_has_dock_bay(arrive_from_ship)) { Int3(); return; } // get the ship that's marked int marked_ship = (player_ship >= 0) ? player_ship : single_ship; dlg.m_arrival = true; dlg.m_ship_class = Ships[arrive_from_ship].ship_info_index; dlg.m_path_mask = &Ships[marked_ship].arrival_path_mask; dlg.DoModal(); } // Goober5000 void CShipEditorDlg::OnRestrictDeparture() { int depart_to_ship; CComboBox *box; restrict_paths dlg; // grab stuff from GUI UpdateData(TRUE); if (m_departure_location != DEPART_AT_DOCK_BAY) { Int3(); return; } box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_TARGET); if (box->GetCount() == 0) return; depart_to_ship = box->GetItemData(m_departure_target); if (!ship_has_dock_bay(depart_to_ship)) { Int3(); return; } // get the ship that's marked int marked_ship = (player_ship >= 0) ? player_ship : single_ship; dlg.m_arrival = false; dlg.m_ship_class = Ships[depart_to_ship].ship_info_index; dlg.m_path_mask = &Ships[marked_ship].departure_path_mask; dlg.DoModal(); }