1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "stdafx.h"
13 #include "FRED.h"
14 
15 #include "FREDDoc.h"
16 #include "FREDView.h"
17 #include "FredRender.h"
18 #include "cfile/cfile.h"
19 #include "Grid.h"
20 #include "MainFrm.h"
21 #include "editor.h"
22 #include "Management.h"
23 #include "graphics/2d.h"
24 #include "render/3d.h"
25 #include "object/object.h"
26 #include "globalincs/linklist.h"
27 #include "math/fvi.h"	//	For find_plane_line_intersection
28 #include "math/vecmat.h"
29 #include "io/key.h"
30 #include "ai/ailocal.h"
31 #include "ai/ai.h"
32 #include "ai/aigoals.h"
33 #include "ship/ship.h"	// for ship names
34 #include "MissionGoalsDlg.h"
35 #include "wing.h"
36 #include "ship_select.h"
37 #include "PlayerStartEditor.h"
38 #include "OrientEditor.h"
39 #include "EventEditor.h"
40 #include "MessageEditorDlg.h"
41 #include "starfield/starfield.h"
42 #include "StarfieldEditor.h"
43 #include "math/floating.h"
44 #include "ReinforcementEditorDlg.h"
45 #include "AsteroidEditorDlg.h"
46 #include "CampaignTreeWnd.h"
47 #include "DebriefingEditorDlg.h"
48 #include "AdjustGridDlg.h"
49 #include "ShieldSysDlg.h"
50 #include "CmdBrief.h"
51 #include "jumpnode/jumpnode.h"
52 #include "DumpStats.h"
53 #include "SetGlobalShipFlags.h"
54 #include "VoiceActingManager.h"
55 #include "FictionViewerDlg.h"
56 #include "cmdline/cmdline.h"
57 #include "object/objectdock.h"
58 #include "species_defs/species_defs.h"
59 #include "sound/audiostr.h"
60 
61 #include "osapi/osapi.h"
62 
63 #include "gl/gl.h"
64 #include "gl/glu.h"
65 
66 #ifdef _DEBUG
67 #undef THIS_FILE
68 static char THIS_FILE[] = __FILE__;
69 #endif
70 
71 subsys_to_render Render_subsys;
72 
73 // the next variable is used for executable stamping -- please leave it alone!!!
74 #define FRED_EXPIRE_TIME	(7 * 1000)
75 char stamp[STAMP_STRING_LENGTH] = { STAMP_STRING };
76 int expire_game;
77 
78 #define EXPIRE_BAD_CHECKSUM			1
79 #define EXPIRE_BAD_TIME					2
80 
81 #define SHIP_TYPES			8000
82 #define REDUCER				100.0f
83 #define DUP_DRAG_OF_WING	2
84 
85 LOCAL int Duped_wing;
86 
87 int Autosave_disabled = 0;
88 int Show_sexp_help = 1;
89 int Show_ships = 1;
90 int Show_starts = 1;
91 int Show_ship_info = 1;
92 int Show_ship_models = 1;
93 int Show_compass = 1;
94 int Show_dock_points = 0;
95 int Show_paths_fred = 0;
96 int Lighting_on = 0;
97 int FullDetail = 0;
98 int Selection_lock = 0;
99 int viewpoint = 0;
100 int view_obj;
101 int button_down = 0;
102 int Marked = 0, moved = 0;
103 int on_object = -1;
104 int Cursor_over = -1;
105 int Dup_drag = 0;
106 int physics_speed = 1;
107 int physics_rot = 20;
108 int box_marking = 0;
109 int last_mouse_x, last_mouse_y, mouse_dx, mouse_dy;
110 int Cur_bitmap = -1;
111 int Id_select_type_jump_node;
112 int Id_select_type_start = 0;
113 int Id_select_type_waypoint = 0;
114 int Hide_ship_cues = 0, Hide_wing_cues = 0;
115 vec3d original_pos, saved_cam_pos;
116 matrix bitmap_matrix_backup, saved_cam_orient = { 0.0f };
117 Marking_box	marking_box;
118 object_orient_pos	rotation_backup[MAX_OBJECTS];
119 
120 // Goober5000 (currently, FS1 retail not implemented)
121 int Format_fs2_open = FSO_FORMAT_STANDARD;
122 int Format_fs2_retail = 0;
123 int Format_fs1_retail = 0;
124 
125 // used by error checker, but needed in more than just one function.
126 char *names[MAX_OBJECTS], flags[MAX_OBJECTS];
127 int obj_count = 0;
128 int g_err = 0;
129 
130 int ID_SHOW_IFF[MAX_IFFS];
131 
132 void view_universe(int just_marked = 0);
133 void select_objects();
134 void drag_rotate_save_backup();
135 
136 /////////////////////////////////////////////////////////////////////////////
137 // CFREDView
138 
139 CFREDView *Fred_view_wnd = NULL;
140 
IMPLEMENT_DYNCREATE(CFREDView,CView)141 IMPLEMENT_DYNCREATE(CFREDView, CView)
142 
143 BEGIN_MESSAGE_MAP(CFREDView, CView)
144 	ON_MESSAGE(WM_GOODBYE, OnGoodbye)
145 	ON_MESSAGE(WM_MENU_POPUP_SHIPS, OnMenuPopupShips)
146 	ON_MESSAGE(WM_MENU_POPUP_EDIT, OnMenuPopupEdit)
147 
148 	//{{AFX_MSG_MAP(CFREDView)
149 	ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
150 	ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
151 	ON_COMMAND(ID_SHOW_WAYPOINTS, OnViewWaypoints)
152 	ON_UPDATE_COMMAND_UI(ID_SHOW_WAYPOINTS, OnUpdateViewWaypoints)
153 	ON_WM_LBUTTONDOWN()
154 	ON_COMMAND(ID_EDITORS_SHIPS, OnEditorsShips)
155 	ON_WM_KEYDOWN()
156 	ON_WM_KEYUP()
157 	ON_WM_SETFOCUS()
158 	ON_WM_KILLFOCUS()
159 	ON_WM_SIZE()
160 	ON_WM_MOUSEMOVE()
161 	ON_WM_LBUTTONUP()
162 	ON_COMMAND(ID_MISCSTUFF_SHOWSHIPSASICONS, OnMiscstuffShowshipsasicons)
163 	ON_WM_CONTEXTMENU()
164 	ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnEditPopupShowShipIcons)
165 	ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnUpdateEditPopupShowShipIcons)
166 	ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnEditPopupShowShipModels)
167 	ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnUpdateEditPopupShowShipModels)
168 	ON_COMMAND(ID_MISC_STATISTICS, OnMiscStatistics)
169 	ON_COMMAND(ID_EDIT_POPUP_SHOW_COMPASS, OnEditPopupShowCompass)
170 	ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_COMPASS, OnUpdateEditPopupShowCompass)
171 	ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_EXTERNAL, OnUpdateChangeViewpointExternal)
172 	ON_COMMAND(ID_CHANGE_VIEWPOINT_EXTERNAL, OnChangeViewpointExternal)
173 	ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_FOLLOW, OnUpdateChangeViewpointFollow)
174 	ON_COMMAND(ID_CHANGE_VIEWPOINT_FOLLOW, OnChangeViewpointFollow)
175 	ON_COMMAND(ID_EDITORS_GOALS, OnEditorsGoals)
176 	ON_COMMAND(ID_SPEED1, OnSpeed1)
177 	ON_COMMAND(ID_SPEED2, OnSpeed2)
178 	ON_COMMAND(ID_SPEED5, OnSpeed5)
179 	ON_COMMAND(ID_SPEED10, OnSpeed10)
180 	ON_UPDATE_COMMAND_UI(ID_SPEED1, OnUpdateSpeed1)
181 	ON_COMMAND(ID_SPEED3, OnSpeed3)
182 	ON_COMMAND(ID_SPEED8, OnSpeed8)
183 	ON_COMMAND(ID_ROT1, OnRot1)
184 	ON_COMMAND(ID_ROT2, OnRot2)
185 	ON_COMMAND(ID_ROT3, OnRot3)
186 	ON_COMMAND(ID_ROT4, OnRot4)
187 	ON_COMMAND(ID_ROT5, OnRot5)
188 	ON_UPDATE_COMMAND_UI(ID_SPEED2, OnUpdateSpeed2)
189 	ON_UPDATE_COMMAND_UI(ID_SPEED3, OnUpdateSpeed3)
190 	ON_UPDATE_COMMAND_UI(ID_SPEED5, OnUpdateSpeed5)
191 	ON_UPDATE_COMMAND_UI(ID_SPEED8, OnUpdateSpeed8)
192 	ON_UPDATE_COMMAND_UI(ID_SPEED10, OnUpdateSpeed10)
193 	ON_UPDATE_COMMAND_UI(ID_ROT1, OnUpdateRot1)
194 	ON_UPDATE_COMMAND_UI(ID_ROT2, OnUpdateRot2)
195 	ON_UPDATE_COMMAND_UI(ID_ROT3, OnUpdateRot3)
196 	ON_UPDATE_COMMAND_UI(ID_ROT4, OnUpdateRot4)
197 	ON_UPDATE_COMMAND_UI(ID_ROT5, OnUpdateRot5)
198 	ON_COMMAND(ID_CONTROL_MODE_CAMERA, OnControlModeCamera)
199 	ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_CAMERA, OnUpdateControlModeCamera)
200 	ON_COMMAND(ID_CONTROL_MODE_SHIP, OnControlModeShip)
201 	ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_SHIP, OnUpdateControlModeShip)
202 	ON_COMMAND(ID_SHOW_GRID_POSITIONS, OnShowGridPositions)
203 	ON_UPDATE_COMMAND_UI(ID_SHOW_GRID_POSITIONS, OnUpdateShowGridPositions)
204 	ON_COMMAND(ID_SHOW_COORDINATES, OnShowCoordinates)
205 	ON_UPDATE_COMMAND_UI(ID_SHOW_COORDINATES, OnUpdateShowCoordinates)
206 	ON_COMMAND(ID_SPEED50, OnSpeed50)
207 	ON_UPDATE_COMMAND_UI(ID_SPEED50, OnUpdateSpeed50)
208 	ON_COMMAND(ID_SPEED100, OnSpeed100)
209 	ON_UPDATE_COMMAND_UI(ID_SPEED100, OnUpdateSpeed100)
210 	ON_COMMAND(ID_SELECT, OnSelect)
211 	ON_UPDATE_COMMAND_UI(ID_SELECT, OnUpdateSelect)
212 	ON_COMMAND(ID_SELECT_AND_MOVE, OnSelectAndMove)
213 	ON_UPDATE_COMMAND_UI(ID_SELECT_AND_MOVE, OnUpdateSelectAndMove)
214 	ON_COMMAND(ID_SELECT_AND_ROTATE, OnSelectAndRotate)
215 	ON_UPDATE_COMMAND_UI(ID_SELECT_AND_ROTATE, OnUpdateSelectAndRotate)
216 	ON_COMMAND(ID_CONSTRAIN_X, OnConstrainX)
217 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_X, OnUpdateConstrainX)
218 	ON_COMMAND(ID_CONSTRAIN_Y, OnConstrainY)
219 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Y, OnUpdateConstrainY)
220 	ON_COMMAND(ID_CONSTRAIN_Z, OnConstrainZ)
221 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Z, OnUpdateConstrainZ)
222 	ON_COMMAND(ID_CONSTRAIN_XZ, OnConstrainXz)
223 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XZ, OnUpdateConstrainXz)
224 	ON_COMMAND(ID_SELECTION_LOCK, OnSelectionLock)
225 	ON_UPDATE_COMMAND_UI(ID_SELECTION_LOCK, OnUpdateSelectionLock)
226 	ON_WM_LBUTTONDBLCLK()
227 	ON_COMMAND(ID_DOUBLE_FINE_GRIDLINES, OnDoubleFineGridlines)
228 	ON_UPDATE_COMMAND_UI(ID_DOUBLE_FINE_GRIDLINES, OnUpdateDoubleFineGridlines)
229 	ON_COMMAND(ID_SHOW_DISTANCES, OnShowDistances)
230 	ON_UPDATE_COMMAND_UI(ID_SHOW_DISTANCES, OnUpdateShowDistances)
231 	ON_COMMAND(ID_UNIVERSAL_HEADING, OnUniversalHeading)
232 	ON_UPDATE_COMMAND_UI(ID_UNIVERSAL_HEADING, OnUpdateUniversalHeading)
233 	ON_COMMAND(ID_FLYING_CONTROLS, OnFlyingControls)
234 	ON_UPDATE_COMMAND_UI(ID_FLYING_CONTROLS, OnUpdateFlyingControls)
235 	ON_COMMAND(ID_ROTATE_LOCALLY, OnRotateLocally)
236 	ON_UPDATE_COMMAND_UI(ID_ROTATE_LOCALLY, OnUpdateRotateLocally)
237 	ON_COMMAND(ID_CONSTRAIN_XY, OnConstrainXy)
238 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XY, OnUpdateConstrainXy)
239 	ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_YZ, OnUpdateConstrainYz)
240 	ON_COMMAND(ID_CONSTRAIN_YZ, OnConstrainYz)
241 	ON_COMMAND(ID_SELECT_LIST, OnSelectList)
242 	ON_COMMAND(ID_ZOOM_EXTENTS, OnZoomExtents)
243 	ON_COMMAND(ID_ZOOM_SELECTED, OnZoomSelected)
244 	ON_UPDATE_COMMAND_UI(ID_ZOOM_SELECTED, OnUpdateZoomSelected)
245 	ON_COMMAND(ID_FORM_WING, OnFormWing)
246 	ON_UPDATE_COMMAND_UI(ID_FORM_WING, OnUpdateFormWing)
247 	ON_COMMAND(ID_DISBAND_WING, OnDisbandWing)
248 	ON_UPDATE_COMMAND_UI(ID_DISBAND_WING, OnUpdateDisbandWing)
249 	ON_COMMAND(ID_SHOW_HORIZON, OnShowHorizon)
250 	ON_UPDATE_COMMAND_UI(ID_SHOW_HORIZON, OnUpdateShowHorizon)
251 	ON_COMMAND(ID_EDITORS_WING, OnEditorsWing)
252 	ON_COMMAND(ID_EDITORS_PLAYER, OnEditorsPlayer)
253 	ON_COMMAND(ID_EDITORS_ORIENT, OnEditorsOrient)
254 	ON_COMMAND(ID_EDITORS_EVENTS, OnEditorsEvents)
255 	ON_UPDATE_COMMAND_UI(ID_EDITORS_ORIENT, OnUpdateEditorsOrient)
256 	ON_COMMAND(ID_EDITORS_MESSAGE, OnEditorsMessage)
257 	ON_COMMAND(ID_EDITORS_STARFIELD, OnEditorsStarfield)
258 	ON_COMMAND(ID_EDITORS_BG_BITMAPS, OnEditorsBgBitmaps)
259 	ON_COMMAND(ID_EDITORS_REINFORCEMENT, OnEditorsReinforcement)
260 	ON_COMMAND(ID_ERROR_CHECKER, OnErrorChecker)
261 	ON_COMMAND(ID_EDITORS_WAYPOINT, OnEditorsWaypoint)
262 	ON_COMMAND(ID_VIEW_OUTLINES, OnViewOutlines)
263 	ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINES, OnUpdateViewOutlines)
264 	ON_UPDATE_COMMAND_UI(ID_NEW_SHIP_TYPE, OnUpdateNewShipType)
265 	ON_COMMAND(ID_SHOW_STARFIELD, OnShowStarfield)
266 	ON_UPDATE_COMMAND_UI(ID_SHOW_STARFIELD, OnUpdateShowStarfield)
267 	ON_COMMAND(ID_ASTEROID_EDITOR, OnAsteroidEditor)
268 	ON_COMMAND(ID_RUN_FREESPACE, OnRunFreeSpace)
269 	ON_COMMAND(ID_EDITOR_CAMPAIGN, OnEditorCampaign)
270 	ON_COMMAND(ID_SHOW_SHIPS, OnShowShips)
271 	ON_UPDATE_COMMAND_UI(ID_SHOW_SHIPS, OnUpdateShowShips)
272 	ON_COMMAND(ID_SHOW_STARTS, OnShowStarts)
273 	ON_UPDATE_COMMAND_UI(ID_SHOW_STARTS, OnUpdateShowStarts)
274 	ON_COMMAND(ID_SHOW_IFF_0, OnShowIFF0)
275 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_0, OnUpdateShowIFF0)
276 	ON_COMMAND(ID_SHOW_IFF_1, OnShowIFF1)
277 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_1, OnUpdateShowIFF1)
278 	ON_COMMAND(ID_SHOW_IFF_2, OnShowIFF2)
279 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_2, OnUpdateShowIFF2)
280 	ON_COMMAND(ID_SHOW_IFF_3, OnShowIFF3)
281 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_3, OnUpdateShowIFF3)
282 	ON_COMMAND(ID_SHOW_IFF_4, OnShowIFF4)
283 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_4, OnUpdateShowIFF4)
284 	ON_COMMAND(ID_SHOW_IFF_5, OnShowIFF5)
285 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_5, OnUpdateShowIFF5)
286 	ON_COMMAND(ID_SHOW_IFF_6, OnShowIFF6)
287 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_6, OnUpdateShowIFF6)
288 	ON_COMMAND(ID_SHOW_IFF_7, OnShowIFF7)
289 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_7, OnUpdateShowIFF7)
290 	ON_COMMAND(ID_SHOW_IFF_8, OnShowIFF8)
291 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_8, OnUpdateShowIFF8)
292 	ON_COMMAND(ID_SHOW_IFF_9, OnShowIFF9)
293 	ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_9, OnUpdateShowIFF9)
294 	ON_COMMAND(ID_TOGGLE_VIEWPOINT, OnToggleViewpoint)
295 	ON_COMMAND(ID_REVERT, OnRevert)
296 	ON_UPDATE_COMMAND_UI(ID_REVERT, OnUpdateRevert)
297 	ON_WM_SETCURSOR()
298 	ON_COMMAND(ID_HIDE_OBJECTS, OnHideObjects)
299 	ON_COMMAND(ID_SHOW_HIDDEN_OBJECTS, OnShowHiddenObjects)
300 	ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
301 	ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
302 	ON_COMMAND(ID_EDITORS_BRIEFING, OnEditorsBriefing)
303 	ON_COMMAND(ID_EDITORS_DEBRIEFING, OnEditorsDebriefing)
304 	ON_COMMAND(ID_SAVE_CAMERA, OnSaveCamera)
305 	ON_COMMAND(ID_RESTORE_CAMERA, OnRestoreCamera)
306 	ON_UPDATE_COMMAND_UI(ID_RESTORE_CAMERA, OnUpdateRestoreCamera)
307 	ON_COMMAND(ID_SHOW_SEXP_HELP, OnShowSexpHelp)
308 	ON_UPDATE_COMMAND_UI(ID_SHOW_SEXP_HELP, OnUpdateShowSexpHelp)
309 	ON_COMMAND(ID_LOOKAT_OBJ, OnLookatObj)
310 	ON_UPDATE_COMMAND_UI(ID_LOOKAT_OBJ, OnUpdateLookatObj)
311 	ON_COMMAND(ID_EDITORS_ADJUST_GRID, OnEditorsAdjustGrid)
312 	ON_COMMAND(ID_EDITORS_SHIELD_SYS, OnEditorsShieldSys)
313 	ON_COMMAND(ID_LEVEL_OBJ, OnLevelObj)
314 	ON_COMMAND(ID_ALIGN_OBJ, OnAlignObj)
315 	ON_COMMAND(ID_CONTROL_OBJ, OnControlObj)
316 	ON_COMMAND(ID_NEXT_OBJ, OnNextObj)
317 	ON_COMMAND(ID_PREV_OBJ, OnPrevObj)
318 	ON_COMMAND(ID_EDIT_DELETE_WING, OnEditDeleteWing)
319 	ON_COMMAND(ID_MARK_WING, OnMarkWing)
320 	ON_UPDATE_COMMAND_UI(ID_CONTROL_OBJ, OnUpdateControlObj)
321 	ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
322 	ON_COMMAND(ID_AA_GRIDLINES, OnAaGridlines)
323 	ON_UPDATE_COMMAND_UI(ID_AA_GRIDLINES, OnUpdateAaGridlines)
324 	ON_COMMAND(ID_EDITORS_CMD_BRIEF, OnCmdBrief)
325 	ON_COMMAND(ID_DISABLE_UNDO, OnDisableUndo)
326 	ON_UPDATE_COMMAND_UI(ID_DISABLE_UNDO, OnUpdateDisableUndo)
327 	ON_UPDATE_COMMAND_UI(ID_EDITORS_CMD_BRIEF, OnUpdateCmdBrief)
328 	ON_COMMAND(ID_NEXT_SUBSYS, OnNextSubsys)
329 	ON_COMMAND(ID_PREV_SUBSYS, OnPrevSubsys)
330 	ON_COMMAND(ID_CANCEL_SUBSYS, OnCancelSubsys)
331 	ON_COMMAND(ID_DUMP_STATS, OnDumpStats)
332 	ON_COMMAND(ID_SHOW_PATHS, OnShowPaths)
333 	ON_UPDATE_COMMAND_UI(ID_SHOW_PATHS, OnUpdateShowPaths)
334 	ON_COMMAND(ID_SHOW_DOCK_POINTS, OnShowDockPoints)
335 	ON_UPDATE_COMMAND_UI(ID_SHOW_DOCK_POINTS, OnUpdateShowDockPoints)
336 	ON_COMMAND(ID_FORMAT_FS2_OPEN, OnFormatFs2Open)
337 	ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_OPEN, OnUpdateFormatFs2Open)
338 	ON_COMMAND(ID_FORMAT_FS2_OPEN_COMP, OnFormatFs2OpenComp)
339 	ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_OPEN_COMP, OnUpdateFormatFs2OpenComp)
340 	ON_COMMAND(ID_FORMAT_FS2_RETAIL, OnFormatFs2Retail)
341 	ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_RETAIL, OnUpdateFormatFs2Retail)
342 	ON_COMMAND(ID_FORMAT_FS1_RETAIL, OnFormatFs1Retail)
343 	ON_UPDATE_COMMAND_UI(ID_FORMAT_FS1_RETAIL, OnUpdateFormatFs1Retail)
344 	ON_COMMAND(ID_EDITORS_SET_GLOBAL_SHIP_FLAGS, OnEditorsSetGlobalShipFlags)
345 	ON_COMMAND(ID_EDITORS_VOICE, OnEditorsVoiceManager)
346 	ON_COMMAND(ID_EDITORS_FICTION, OnEditorsFiction)
347 	ON_WM_DESTROY()
348 	ON_WM_CREATE()
349 	ON_WM_ERASEBKGND()
350 	ON_COMMAND(ID_VIEW_LIGHTING, OnViewLighting)
351 	ON_UPDATE_COMMAND_UI(ID_VIEW_LIGHTING, OnUpdateViewLighting)
352 	ON_COMMAND(ID_VIEW_FULL_DETAIL, OnViewFullDetail)
353 	ON_UPDATE_COMMAND_UI(ID_VIEW_FULL_DETAIL, OnUpdateViewFullDetail)
354 	//}}AFX_MSG_MAP
355 	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
356 	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
357 	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
358 	ON_COMMAND_RANGE(ID_GROUP1, ID_GROUP9, OnGroup)
359 	ON_COMMAND_RANGE(ID_SET_GROUP1, ID_SET_GROUP9, OnSetGroup)
360 END_MESSAGE_MAP()
361 
362 /////////////////////////////////////////////////////////////////////////////
363 // CFREDView construction/destruction
364 
365 CFREDView::CFREDView()
366 {
367 	//m_ConfirmDeleting = TRUE;
368 	//m_ShowCapitalShips = TRUE;
369 	//m_ShowElevations = TRUE;
370 	//m_ShowFighters = TRUE;
371 	//m_ShowGrid = TRUE;
372 	//m_ShowMiscObjects = TRUE;
373 	//m_ShowPlanets = TRUE;
374 	//m_ShowWaypoints = TRUE;
375 
376 	// this is stupid
377 	ID_SHOW_IFF[0] = ID_SHOW_IFF_0;
378 	ID_SHOW_IFF[1] = ID_SHOW_IFF_1;
379 	ID_SHOW_IFF[2] = ID_SHOW_IFF_2;
380 	ID_SHOW_IFF[3] = ID_SHOW_IFF_3;
381 	ID_SHOW_IFF[4] = ID_SHOW_IFF_4;
382 	ID_SHOW_IFF[5] = ID_SHOW_IFF_5;
383 	ID_SHOW_IFF[6] = ID_SHOW_IFF_6;
384 	ID_SHOW_IFF[7] = ID_SHOW_IFF_7;
385 	ID_SHOW_IFF[8] = ID_SHOW_IFF_8;
386 	ID_SHOW_IFF[9] = ID_SHOW_IFF_9;
387 
388 	m_pGDlg = new CGrid(this);
389 
390 	//if (!(int errno = gr_init(640, 480, 32)))
391 	//	Error(LOCATION, "Hey, gr_init failed! Error code = %i", errno);
392 	Fred_view_wnd = this;
393 }
394 
~CFREDView()395 CFREDView::~CFREDView()
396 {
397 	delete m_pGDlg;
398 }
399 
expire_game_proc(HWND wnd,UINT uMsg,UINT idEvent,DWORD dwTime)400 void CALLBACK expire_game_proc( HWND wnd, UINT uMsg, UINT idEvent, DWORD dwTime)
401 {
402 	KillTimer(wnd, 1);
403 	if ( expire_game == EXPIRE_BAD_CHECKSUM )
404 		MessageBox (wnd, "Fred can no longer run due to internal overlay error", NULL, MB_OK | MB_ICONERROR |MB_TASKMODAL|MB_SETFOREGROUND);
405 	else
406 		MessageBox (wnd, "Error: cannot enter DOS mode for 80x40 color text mode display.", NULL, MB_OK | MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND);
407 	exit(1);
408 }
409 
PreCreateWindow(CREATESTRUCT & cs)410 BOOL CFREDView::PreCreateWindow(CREATESTRUCT& cs)
411 {
412 	BOOL casperl;
413 
414 	casperl = CView::PreCreateWindow(cs);
415 	cs.y = 0;  // doesn't seem to do anything. :(
416 
417 // other miscellaneous initializations
418 
419 	if (Cmdline_mod)
420 		cfile_chdir(Cmdline_mod);
421 	cfile_chdir("data\\missions");
422 
423 
424 	set_physics_controls();
425 	return casperl;
426 }
427 
428 /////////////////////////////////////////////////////////////////////////////
429 // CFREDView drawing
430 
OnDraw(CDC * pDC)431 void CFREDView::OnDraw(CDC* pDC)
432 {
433 	CRect clip;
434 
435 	CFREDDoc* pDoc = GetDocument();
436 	ASSERT_VALID(pDoc);
437 
438 	Update_window = 1;
439 }
440 
441 /////////////////////////////////////////////////////////////////////////////
442 // CFREDView printing
443 
OnPreparePrinting(CPrintInfo * pInfo)444 BOOL CFREDView::OnPreparePrinting(CPrintInfo* pInfo)
445 {
446 	// default preparation
447 	return DoPreparePrinting(pInfo);
448 }
449 
OnBeginPrinting(CDC *,CPrintInfo *)450 void CFREDView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
451 {
452 	// TODO: add extra initialization before printing
453 }
454 
OnEndPrinting(CDC *,CPrintInfo *)455 void CFREDView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
456 {
457 	// TODO: add cleanup after printing
458 }
459 
460 /////////////////////////////////////////////////////////////////////////////
461 // CFREDView diagnostics
462 
463 #ifdef _DEBUG
AssertValid() const464 void CFREDView::AssertValid() const
465 {
466 	CView::AssertValid();
467 }
468 
Dump(CDumpContext & dc) const469 void CFREDView::Dump(CDumpContext& dc) const
470 {
471 	CView::Dump(dc);
472 }
473 
GetDocument()474 CFREDDoc* CFREDView::GetDocument() // non-debug version is inline
475 {
476 	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFREDDoc)));
477 	return (CFREDDoc*)m_pDocument;
478 }
479 #endif //_DEBUG
480 
481 /////////////////////////////////////////////////////////////////////////////
482 // CFREDView message handlers
483 
OnViewGrid()484 void CFREDView::OnViewGrid()
485 {
486 	Show_grid = !Show_grid;
487 	Update_window = 1;
488 }
489 
OnUpdateViewGrid(CCmdUI * pCmdUI)490 void CFREDView::OnUpdateViewGrid(CCmdUI* pCmdUI)
491 {
492 	pCmdUI->SetCheck(Show_grid);
493 }
494 
OnViewWaypoints()495 void CFREDView::OnViewWaypoints()
496 {
497 	Show_waypoints = !Show_waypoints;
498 	Update_window = 1;
499 }
500 
OnUpdateViewWaypoints(CCmdUI * pCmdUI)501 void CFREDView::OnUpdateViewWaypoints(CCmdUI* pCmdUI)
502 {
503 	pCmdUI->SetCheck(Show_waypoints);
504 }
505 
506 #define MAX_MOVE_DISTANCE 25.0f
507 
508 //	If cur_object_index references a valid object, drag it from its current
509 //	location to the new cursor location specified by "point".
510 //	It is dragged relative to the main grid.  Its y coordinate is not changed.
511 //	Return value: 0/1 = didn't/did move object all the way to goal.
drag_objects()512 int drag_objects()
513 {
514 	int z, cobj, flag, rval = 1;
515 	float r;
516 	float	distance_moved = 0.0f;
517 	vec3d cursor_dir, int_pnt;
518 	vec3d movement_vector;
519 	vec3d obj;
520 	vec3d vec1, vec2;
521 	object *objp, *ptr;
522 	// starfield_bitmaps *bmp;
523 
524 	/*
525 	if (Bg_bitmap_dialog) {
526 		if (Cur_bitmap < 0)
527 			return -1;
528 
529 		bmp = &Starfield_bitmaps[Cur_bitmap];
530 		if (Single_axis_constraint && Constraint.z) {
531 			bmp->dist *= 1.0f + mouse_dx / -800.0f;
532 			calculate_bitmap_points(bmp, 0.0f);
533 
534 		} else {
535 			g3_point_to_vec_delayed(&bmp->m.fvec, marking_box.x2, marking_box.y2);
536 			vm_orthogonalize_matrix(&bmp->m);
537 			calculate_bitmap_points(bmp, 0.0f);
538 		}
539 		return rval;
540 	}
541 	*/
542 
543 	if (!query_valid_object())
544 		return -1;
545 
546 	if ((Dup_drag == 1) && (Briefing_dialog))
547 		Dup_drag = 0;
548 
549 	if (Dup_drag == 1) {
550 		dup_object(NULL);  // reset waypoint list
551 		cobj = Duped_wing = -1;
552 		flag = 0;
553 		objp = GET_FIRST(&obj_used_list);
554 		while (objp != END_OF_LIST(&obj_used_list))	{
555 			Assert(objp->type != OBJ_NONE);
556 			if (objp->flags & OF_MARKED) {
557 				if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
558 					z = Ships[objp->instance].wingnum;
559 					if (!flag)
560 						Duped_wing = z;
561 					else if (Duped_wing != z)
562 						Duped_wing = -1;
563 
564 				} else
565 					Duped_wing = -1;
566 
567 				flag = 1;
568 				z = dup_object(objp);
569 				if (z == -1) {
570 					cobj = -1;
571 					break;
572 				}
573 
574 				if (cur_object_index == OBJ_INDEX(objp) )
575 					cobj = z;
576 			}
577 
578 			objp = GET_NEXT(objp);
579 		}
580 
581 		obj_merge_created_list();
582 		if (cobj == -1) {
583 			objp = GET_FIRST(&obj_used_list);
584 			while (objp != END_OF_LIST(&obj_used_list))	{
585 				ptr = GET_NEXT(objp);
586 				if (objp->flags & OF_TEMP_MARKED)
587 					delete_object(objp);
588 
589 				objp = ptr;
590 			}
591 
592 			button_down = 0;
593 			return -1;
594 		}
595 
596 		unmark_all();
597 
598 		objp = GET_FIRST(&obj_used_list);
599 		while (objp != END_OF_LIST(&obj_used_list))	{
600 			if (objp->flags & OF_TEMP_MARKED) {
601 				objp->flags &= ~OF_TEMP_MARKED;
602 				mark_object(OBJ_INDEX(objp));
603 			}
604 
605 			objp = GET_NEXT(objp);
606 		}
607 
608 		set_cur_object_index(cobj);
609 		if (Duped_wing != -1)
610 			Dup_drag = DUP_DRAG_OF_WING;  // indication for later that we duped objects in a wing
611 		else
612 			Dup_drag = 0;
613 
614 		drag_rotate_save_backup();
615 		set_modified();
616 		Update_window = 1;
617 	}
618 
619 	objp = &Objects[cur_object_index];
620 	Assert(objp->type != OBJ_NONE);
621 	obj = int_pnt = objp->pos;
622 
623 	//	Get 3d vector specified by mouse cursor location.
624 	g3_point_to_vec_delayed(&cursor_dir, marking_box.x2, marking_box.y2);
625 	if (Single_axis_constraint)	{
626 //		if (fvi_ray_plane(&int_pnt, &obj, &view_orient.fvec, &view_pos, &cursor_dir, 0.0f) >= 0.0f )	{
627 //			vm_vec_add(&p1, &obj, &Constraint);
628 //			find_nearest_point_on_line(&nearest_point, &obj, &p1, &int_pnt);
629 //			int_pnt = nearest_point;
630 //			distance_moved = vm_vec_dist(&obj, &int_pnt);
631 //		}
632 
633 		vec3d tmpAnticonstraint = Anticonstraint;
634 		vec3d tmpObject = obj;
635 
636 		tmpAnticonstraint.xyz.x = 0.0f;
637 		r = fvi_ray_plane(&int_pnt, &tmpObject, &tmpAnticonstraint, &view_pos, &cursor_dir, 0.0f);
638 
639 		//	If intersected behind viewer, don't move.  Too confusing, not what user wants.
640 		vm_vec_sub(&vec1, &int_pnt, &view_pos);
641 		vm_vec_sub(&vec2, &obj, &view_pos);
642 		if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f))	{
643 			vec3d tmp1;
644 			vm_vec_sub( &tmp1, &int_pnt, &obj );
645 			tmp1.xyz.x *= Constraint.xyz.x;
646 			tmp1.xyz.y *= Constraint.xyz.y;
647 			tmp1.xyz.z *= Constraint.xyz.z;
648 			vm_vec_add( &int_pnt, &obj, &tmp1 );
649 
650 			distance_moved = vm_vec_dist(&obj, &int_pnt);
651 		}
652 
653 
654 	} else {  // Move in x-z plane, defined by grid.  Preserve height.
655 		r = fvi_ray_plane(&int_pnt, &obj, &Anticonstraint, &view_pos, &cursor_dir, 0.0f);
656 
657 		//	If intersected behind viewer, don't move.  Too confusing, not what user wants.
658 		vm_vec_sub(&vec1, &int_pnt, &view_pos);
659 		vm_vec_sub(&vec2, &obj, &view_pos);
660 		if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f))
661 			distance_moved = vm_vec_dist(&obj, &int_pnt);
662 	}
663 
664 	//	If moved too far, then move max distance along vector.
665 	vm_vec_sub(&movement_vector, &int_pnt, &obj);
666 /*	if (distance_moved > MAX_MOVE_DISTANCE)	{
667 		vm_vec_normalize(&movement_vector);
668 		vm_vec_scale(&movement_vector, MAX_MOVE_DISTANCE);
669 	} */
670 
671 	if (distance_moved) {
672 		objp = GET_FIRST(&obj_used_list);
673 		while (objp != END_OF_LIST(&obj_used_list))	{
674 			Assert(objp->type != OBJ_NONE);
675 			if (objp->flags & OF_MARKED) {
676 				vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
677 				if (objp->type == OBJ_WAYPOINT) {
678 					waypoint *wpt = find_waypoint_with_instance(objp->instance);
679 					Assert(wpt != NULL);
680 					wpt->set_pos(&objp->pos);
681 				}
682 			}
683 
684 			objp = GET_NEXT(objp);
685 		}
686 
687 		objp = GET_FIRST(&obj_used_list);
688 		while (objp != END_OF_LIST(&obj_used_list)) {
689 			if (objp->flags & OF_MARKED)
690 				object_moved(objp);
691 
692 			objp = GET_NEXT(objp);
693 		}
694 	}
695 
696 	if (Briefing_dialog)
697 		Briefing_dialog->update_positions();
698 
699 	set_modified();
700 	return rval;
701 }
702 
drag_rotate_save_backup()703 void drag_rotate_save_backup()
704 {
705 	object *objp;
706 
707 	/*
708 	if (Cur_bitmap != -1)
709 		bitmap_matrix_backup = Starfield_bitmaps[Cur_bitmap].m;
710 		*/
711 
712 	objp = GET_FIRST(&obj_used_list);
713 	while (objp != END_OF_LIST(&obj_used_list))			{
714 		Assert(objp->type != OBJ_NONE);
715 		if (objp->flags & OF_MARKED)	{
716 			rotation_backup[OBJ_INDEX(objp)].pos = objp->pos;
717 			rotation_backup[OBJ_INDEX(objp)].orient = objp->orient;
718 		}
719 
720 		objp = GET_NEXT(objp);
721 	}
722 }
723 
drag_rotate_objects()724 int drag_rotate_objects()
725 {
726 	int rval = 1;
727 	vec3d int_pnt, obj;
728 	angles a;
729 	matrix leader_orient, leader_transpose, tmp, newmat, rotmat;
730 	object *leader, *objp;
731 	// starfield_bitmaps *bmp;
732 
733 	Update_window = 1;
734 	/*
735 	if (Bg_bitmap_dialog) {
736 		if (Cur_bitmap < 0)
737 			return -1;
738 
739 		bmp = &Starfield_bitmaps[Cur_bitmap];
740 		calculate_bitmap_points(bmp, mouse_dx / -300.0f);
741 		return rval;
742 	}
743 	*/
744 
745 	if (!query_valid_object()){
746 		return -1;
747 	}
748 
749 	objp = &Objects[cur_object_index];
750 	Assert(objp->type != OBJ_NONE);
751 	obj = int_pnt = objp->pos;
752 
753 	memset(&a, 0, sizeof(angles));
754 	if (Single_axis_constraint) {
755 		if (Constraint.xyz.x)
756 			a.p = mouse_dy / REDUCER;
757 		else if (Constraint.xyz.y)
758 			a.h = mouse_dx / REDUCER;
759 		else if (Constraint.xyz.z)
760 			a.b = -mouse_dx / REDUCER;
761 
762 	} else {
763 		if (!Constraint.xyz.x) {				// yz
764 			a.b = -mouse_dx / REDUCER;
765 			a.h = mouse_dy / REDUCER;
766 		} else if (!Constraint.xyz.y) {	// xz
767 			a.p = mouse_dy / REDUCER;
768 			a.b = -mouse_dx / REDUCER;
769 		} else if (!Constraint.xyz.z) {	// xy
770 			a.p = mouse_dy / REDUCER;
771 			a.h = mouse_dx / REDUCER;
772 		}
773 	}
774 
775 	leader = &Objects[cur_object_index];
776 	leader_orient = leader->orient;			// save original orientation
777 	vm_copy_transpose_matrix(&leader_transpose, &leader_orient);
778 
779 	vm_angles_2_matrix(&rotmat, &a);
780 	vm_matrix_x_matrix(&newmat, &leader->orient, &rotmat);
781 	leader->orient = newmat;
782 
783 	objp = GET_FIRST(&obj_used_list);
784 	while (objp != END_OF_LIST(&obj_used_list))			{
785 		Assert(objp->type != OBJ_NONE);
786 		if ((objp->flags & OF_MARKED) && (cur_object_index != OBJ_INDEX(objp) )) {
787 			if (Group_rotate) {
788 				matrix rot_trans;
789 				vec3d tmpv1, tmpv2;
790 
791 				// change rotation matrix to rotate in opposite direction.  This rotation
792 				// matrix is what the leader ship has rotated by.
793 				vm_copy_transpose_matrix(&rot_trans, &rotmat);
794 
795 				// get point relative to our point of rotation (make POR the origin).
796 				vm_vec_sub(&tmpv1, &objp->pos, &leader->pos);
797 
798 				// convert point from real-world coordinates to leader's relative coordinate
799 				// system (z=forward vec, y=up vec, x=right vec
800 				vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient);
801 
802 				// now rotate the point by the transpose from above.
803 				vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
804 
805 				// convert point back into real-world coordinates
806 				vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
807 
808 				// and move origin back to real-world origin.  Object is now at its correct
809 				// position.
810 				vm_vec_add(&objp->pos, &leader->pos, &tmpv2);
811 
812 				// Now fix the object's orientation to what it should be.
813 				vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
814 				vm_orthogonalize_matrix(&tmp);  // safety check
815 				objp->orient = tmp;
816 
817 			} else {
818 				vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
819 				objp->orient = tmp;
820 			}
821 		}
822 
823 		objp = GET_NEXT(objp);
824 	}
825 
826 	objp = GET_FIRST(&obj_used_list);
827 	while (objp != END_OF_LIST(&obj_used_list)) {
828 		if (objp->flags & OF_MARKED)
829 			object_moved(objp);
830 
831 		objp = GET_NEXT(objp);
832 	}
833 
834 	set_modified();
835 	return rval;
836 }
837 
cancel_drag()838 void cancel_drag()
839 {
840 	Update_window = 1;
841 
842 	/*
843 	if (Bg_bitmap_dialog) {
844 		Assert(!vm_check_matrix_for_zeros(&bitmap_matrix_backup));
845 		Starfield_bitmaps[Cur_bitmap].m = bitmap_matrix_backup;
846 		calculate_bitmap_points(&Starfield_bitmaps[Cur_bitmap], 0.0f);
847 		button_down = box_marking = 0;
848 		Update_window = 1;
849 		return;
850 	}
851 	*/
852 
853 	if (button_down) {
854 		if (Editing_mode == 1) {
855 			vec3d movement_vector;
856 			object *objp;
857 
858 			if (query_valid_object()) {
859 				objp = &Objects[cur_object_index];
860 				Assert(objp->type != OBJ_NONE);
861 				vm_vec_sub(&movement_vector, &original_pos, &objp->pos);
862 
863 				objp = GET_FIRST(&obj_used_list);
864 				while (objp != END_OF_LIST(&obj_used_list))	{
865 					Assert(objp->type != OBJ_NONE);
866 					if (objp->flags & OF_MARKED)
867 						vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
868 
869 					objp = GET_NEXT(objp);
870 				}
871 			}
872 
873 		} else if (Editing_mode == 2) {
874 			object *objp;
875 
876 			objp = GET_FIRST(&obj_used_list);
877 			while (objp != END_OF_LIST(&obj_used_list))	{
878 				Assert(objp->type != OBJ_NONE);
879 				if (objp->flags & OF_MARKED) {
880 					int obj_index = OBJ_INDEX(objp);
881 
882 					if(!IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.rvec) &&
883 						!IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.uvec) &&
884 						!IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.fvec)){
885 
886 						objp->pos = rotation_backup[obj_index].pos;
887 						objp->orient = rotation_backup[obj_index].orient;
888 					}
889 				}
890 
891 				objp = GET_NEXT(objp);
892 			}
893 		}
894 	}
895 
896 	button_down = box_marking = 0;
897 	if (Briefing_dialog)
898 		Briefing_dialog->update_positions();
899 }
900 
OnLButtonDown(UINT nFlags,CPoint point)901 void CFREDView::OnLButtonDown(UINT nFlags, CPoint point)
902 {
903 	// RT point
904 
905 	int waypoint_instance = -1;
906 
907 	if (!Fred_active) {
908 		CView::OnLButtonDown(nFlags, point);
909 		return;
910 	}
911 
912 	if (cur_waypoint != NULL)
913 	{
914 		Assert(cur_waypoint_list != NULL);
915 		waypoint_instance = Objects[cur_waypoint->get_objnum()].instance;
916 	}
917 
918 	marking_box.x1 = point.x;
919 	marking_box.y1 = point.y;
920 	Dup_drag = 0;
921 
922 	on_object = select_object(point.x, point.y);
923 	button_down = 1;
924 	SetCapture();
925 	drag_rotate_save_backup();
926 
927 	if (nFlags & MK_CONTROL)	{  // add a new object
928 		if (!Bg_bitmap_dialog) {
929 			if (on_object == -1) {
930 				Selection_lock = 0;  // force off selection lock
931 				on_object = create_object_on_grid(waypoint_instance);
932 
933 			} else
934 				Dup_drag = 1;
935 
936 		} else {
937 			/*
938 			Selection_lock = 0;  // force off selection lock
939 			on_object = Cur_bitmap = create_bg_bitmap();
940 			Bg_bitmap_dialog->update_data();
941 			Update_window = 1;
942 			if (Cur_bitmap == -1)
943 				MessageBox("Background bitmap limit reached.\nCan't add more.");
944 			*/
945 		}
946 
947 	} else if (!Selection_lock) {
948 		if (Bg_bitmap_dialog) {
949 			Cur_bitmap = on_object;
950 			Bg_bitmap_dialog -> update_data();
951 
952 		} else if ((nFlags & MK_SHIFT) || (on_object == -1) || !(Objects[on_object].flags & OF_MARKED)) {
953 			if (!(nFlags & MK_SHIFT))
954 				unmark_all();
955 
956 			if (on_object != -1) {
957 				if (Objects[on_object].flags & OF_MARKED)
958 					unmark_object(on_object);
959 				else
960 					mark_object(on_object);
961 			}
962 		}
963 	}
964 
965 	if (query_valid_object())
966 		original_pos = Objects[cur_object_index].pos;
967 
968 	moved = 0;
969 	if (Selection_lock) {
970 		if (Editing_mode == 1)
971 			drag_objects();
972 		else if (Editing_mode == 2)
973 			drag_rotate_objects();
974 
975 		Update_window = 1;
976 	}
977 
978 	if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
979 		Assert(Briefing_dialog);
980 		Briefing_dialog->icon_select(Objects[cur_object_index].instance);
981 
982 	} else {
983 		if (Briefing_dialog)
984 			Briefing_dialog->icon_select(-1);
985 	}
986 
987 	CView::OnLButtonDown(nFlags, point);
988 }
989 
OnMouseMove(UINT nFlags,CPoint point)990 void CFREDView::OnMouseMove(UINT nFlags, CPoint point)
991 {
992 	// RT point
993 
994 	mouse_dx = point.x - last_mouse_x;
995 	mouse_dy = point.y - last_mouse_y;
996 	last_mouse_x = marking_box.x2 = point.x;
997 	last_mouse_y = marking_box.y2 = point.y;
998 	Cursor_over = select_object(point.x, point.y);
999 
1000 	if (!(nFlags & MK_LBUTTON))
1001 		button_down = 0;
1002 
1003 	// The following will cancel a drag operation if another program running in memory
1004 	// happens to jump in and take over (such as new email has arrived popup boxes).
1005 	if (button_down && GetCapture() != this)
1006 		cancel_drag();
1007 
1008 	if (!button_down && GetCapture() == this)
1009 		ReleaseCapture();
1010 
1011 	if (button_down) {
1012 		if (abs(marking_box.x1 - marking_box.x2) > 1 || abs(marking_box.y1 - marking_box.y2) > 1)
1013 			moved = 1;
1014 
1015 		if (moved) {
1016 			if (on_object != -1 || Selection_lock) {
1017 				if (Editing_mode == 1)
1018 					drag_objects();
1019 				else if (Editing_mode == 2)
1020 					drag_rotate_objects();
1021 
1022 			} else if (!Bg_bitmap_dialog)
1023 				box_marking = 1;
1024 
1025 			if (mouse_dx || mouse_dy)
1026 				Update_window = 1;
1027 		}
1028 	}
1029 
1030 	CView::OnMouseMove(nFlags, point);
1031 }
1032 
OnLButtonUp(UINT nFlags,CPoint point)1033 void CFREDView::OnLButtonUp(UINT nFlags, CPoint point)
1034 {
1035 	marking_box.x2 = point.x;
1036 	marking_box.y2 = point.y;
1037 
1038 	if (button_down && GetCapture() != this)
1039 		cancel_drag();
1040 
1041 	if (GetCapture() == this)
1042 		ReleaseCapture();
1043 
1044 	if (button_down) {
1045 		if ((abs(marking_box.x1 - marking_box.x2) > 1) || (abs(marking_box.y1 - marking_box.y2) > 1))
1046 			moved = 1;
1047 
1048 		if (moved) {
1049 			if ((on_object != -1) || Selection_lock) {
1050 				if (Editing_mode == 1)
1051 					drag_objects();
1052 				else if ((Editing_mode == 2) || (Editing_mode == 3))
1053 					drag_rotate_objects();
1054 
1055 				set_modified();
1056 				FREDDoc_ptr->autosave("object move");
1057 
1058 			} else
1059 				box_marking = 1;
1060 		}
1061 
1062 		if (Bg_bitmap_dialog) {
1063 			box_marking = 0;
1064 
1065 		} else {
1066 			if (box_marking) {
1067 				select_objects();
1068 				box_marking = 0;
1069 
1070 			} else if ((!moved && on_object != -1) && !Selection_lock && !(nFlags & MK_SHIFT)) {
1071 				unmark_all();
1072 				mark_object(on_object);
1073 			}
1074 		}
1075 
1076 		button_down = 0;
1077 		Update_window = 1;
1078 		if (Dup_drag == DUP_DRAG_OF_WING) {
1079 			char msg[256];
1080 			int ship;
1081 			object *objp;
1082 
1083 			sprintf(msg, "Add cloned ships to wing %s?", Wings[Duped_wing].name);
1084 			if (MessageBox(msg, "Query", MB_YESNO) == IDYES) {
1085 				objp = GET_FIRST(&obj_used_list);
1086 				while (objp != END_OF_LIST(&obj_used_list))	{
1087 					if (objp->flags & OF_MARKED) {
1088 						if (Wings[Duped_wing].wave_count >= MAX_SHIPS_PER_WING) {
1089 							MessageBox("Max ships per wing limit reached");
1090 							break;
1091 						}
1092 
1093 // Can't do player starts, since only player 1 is currently allowed to be in a wing
1094 
1095 						Assert(objp->type == OBJ_SHIP);
1096 						ship = objp->instance;
1097 						Assert(Ships[ship].wingnum == -1);
1098 						wing_bash_ship_name(Ships[ship].ship_name, Wings[Duped_wing].name,
1099 							Wings[Duped_wing].wave_count + 1);
1100 
1101 						Wings[Duped_wing].ship_index[Wings[Duped_wing].wave_count] = ship;
1102 						Ships[ship].wingnum = Duped_wing;
1103 
1104 						wing_objects[Duped_wing][Wings[Duped_wing].wave_count] = OBJ_INDEX(objp);
1105 						Wings[Duped_wing].wave_count++;
1106 					}
1107 
1108 					objp = GET_NEXT(objp);
1109 				}
1110 			}
1111 		}
1112 	}
1113 
1114 	if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
1115 		Assert(Briefing_dialog);
1116 		Briefing_dialog->icon_select(Objects[cur_object_index].instance);
1117 
1118 	} else {
1119 		if (Briefing_dialog)
1120 			Briefing_dialog->icon_select(-1);
1121 	}
1122 
1123 	CView::OnLButtonUp(nFlags, point);
1124 }
1125 
1126 //	This function never gets called because nothing causes
1127 //	the WM_GOODBYE event to occur.
1128 // False! When you close the Ship Dialog, this function is called! --MK, 8/30/96
OnGoodbye(UINT wParam,LONG lParam)1129 LONG CFREDView::OnGoodbye(UINT wParam, LONG lParam)
1130 {
1131 	Ship_editor_dialog.DestroyWindow();
1132 	Wing_editor_dialog.DestroyWindow();
1133 
1134 	return 0L;
1135 }
1136 
OnEditorsShips()1137 void CFREDView::OnEditorsShips()
1138 {
1139 	int adjust = 0;
1140 
1141 	Assert(Ship_editor_dialog.GetSafeHwnd());
1142 	if (!Show_sexp_help)
1143 		adjust = -SEXP_HELP_BOX_SIZE;
1144 
1145 	if (!theApp.init_window(&Ship_wnd_data, &Ship_editor_dialog, adjust))
1146 		return;
1147 
1148 	Ship_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
1149 		SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
1150 	Ship_editor_dialog.ShowWindow(SW_RESTORE);
1151 }
1152 
OnKeyDown(UINT nChar,UINT nRepCnt,UINT lParam)1153 void CFREDView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT lParam)
1154 {
1155 	uint lKeyData;
1156 
1157 	lKeyData = lParam & 255;          // key data
1158 	if (lParam & 256) lKeyData += 0x80;
1159 	key_mark(lKeyData, 1, 0);
1160 
1161 	CView::OnKeyDown(nChar, nRepCnt, lParam);
1162 }
1163 
OnKeyUp(UINT nChar,UINT nRepCnt,UINT lParam)1164 void CFREDView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT lParam)
1165 {
1166 	uint lKeyData;
1167 
1168 	lKeyData = lParam & 255;          // key data
1169 	if (lParam & 256) lKeyData += 0x80;
1170 	key_mark(lKeyData, 0, 0);
1171 
1172 	CView::OnKeyUp(nChar, nRepCnt, lParam);
1173 }
1174 
OnSetFocus(CWnd * pOldWnd)1175 void CFREDView::OnSetFocus(CWnd* pOldWnd)
1176 {
1177 	static int flag = 0;
1178 
1179 	if (flag)
1180 		return;
1181 
1182 	flag = 1;
1183 	nprintf(("Fred routing", "OnSetFocus() called\n"));
1184 	if (Update_ship) {
1185 		Ship_editor_dialog.initialize_data(1);
1186 		Update_ship = 0;
1187 	}
1188 
1189 	if (Update_wing) {
1190 		Wing_editor_dialog.initialize_data(1);
1191 		Update_wing = 0;
1192 	}
1193 
1194 /*	if (Wing_editor_dialog.verify() == -1)
1195 		return;  // abort
1196 
1197 	if (Ship_editor_dialog.verify() == -1)
1198 		return;  // abort*/
1199 
1200 	if (update_dialog_boxes()) {
1201 		nprintf(("Fred routing", "OnSetFocus() returned (error occured)\n"));
1202 		flag = 0;
1203 		Ship_editor_dialog.bypass_errors = 0;
1204 		Wing_editor_dialog.bypass_errors = 0;
1205 		return;  // abort
1206 	}
1207 
1208 	if (Local_modified) {
1209 		FREDDoc_ptr->autosave("Editing");
1210 		Local_modified = 0;
1211 	}
1212 
1213 	Fred_active = 1;
1214 	CView::OnSetFocus(pOldWnd);
1215 	nprintf(("Fred routing", "Main window focus accepted\n"));
1216 	key_got_focus();
1217 
1218 	Cursor_over = -1;
1219 	if (GetActiveWindow() != Fred_main_wnd) {
1220 
1221 		// If you get this assert make sure code.lib is compiling under the flags FRED and FRED_OGL
1222 		Assert(Fred_main_wnd);
1223 
1224 		Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1225 		nprintf(("Fred routing", "OnSetFocus() had to put main window back on top\n"));
1226 	}
1227 
1228 	flag = 0;
1229 }
1230 
OnKillFocus(CWnd * pNewWnd)1231 void CFREDView::OnKillFocus(CWnd* pNewWnd)
1232 {
1233 	nprintf(("Fred routing", "OnKillFocus() called\n"));
1234 	Fred_active = 0;
1235 	Local_modified = 0;
1236 	CView::OnKillFocus(pNewWnd);
1237 	key_lost_focus();
1238 	Cursor_over = -1;
1239 }
1240 
OnSize(UINT nType,int cx,int cy)1241 void CFREDView::OnSize(UINT nType, int cx, int cy)
1242 {
1243 	CView::OnSize(nType, cx, cy);
1244 
1245 	if (cy > 0) {
1246 		gr_screen_resize(cx, cy);
1247 		RedrawWindow();
1248 	}
1249 }
1250 
do_trackball_stuff(int nFlags,CPoint point)1251 void do_trackball_stuff(int nFlags, CPoint point)
1252 {
1253 	int	btn = 0;
1254 
1255 	if (nFlags & MK_LBUTTON){
1256 		btn |= 1;
1257 	}
1258 	if (nFlags & MK_RBUTTON){
1259 		btn |= 2;
1260 	}
1261 
1262 	move_mouse(btn, point.x, point.y);
1263 }
1264 
1265 //	If add_flag != 0, then add found objects to current wing, else create new wing.
select_objects()1266 void select_objects()
1267 {
1268 	int	x, y, valid, icon_mode = 0;
1269 	vertex	v;
1270 	object	*ptr;
1271 
1272 	if (marking_box.x1 > marking_box.x2) {
1273 		x = marking_box.x1;
1274 		marking_box.x1 = marking_box.x2;
1275 		marking_box.x2 = x;
1276 	}
1277 
1278 	if (marking_box.y1 > marking_box.y2) {
1279 		y = marking_box.y1;
1280 		marking_box.y1 = marking_box.y2;
1281 		marking_box.y2 = y;
1282 	}
1283 
1284 	ptr = GET_FIRST(&obj_used_list);
1285 	while (ptr != END_OF_LIST(&obj_used_list)) {
1286 		valid = 1;
1287 		if (ptr->flags & OF_HIDDEN)
1288 			valid = 0;
1289 
1290 		Assert(ptr->type != OBJ_NONE);
1291 		switch (ptr->type) {
1292 			case OBJ_WAYPOINT:
1293 				if (!Show_waypoints)
1294 					valid = 0;
1295 				break;
1296 
1297 			case OBJ_START:
1298 				if (!Show_starts || !Show_ships)
1299 					valid = 0;
1300 				break;
1301 
1302 			case OBJ_SHIP:
1303 				if (!Show_ships)
1304 					valid = 0;
1305 
1306 				if (!Show_iff[Ships[ptr->instance].team])
1307 					valid = 0;
1308 
1309 				break;
1310 		}
1311 
1312 		g3_rotate_vertex(&v, &ptr->pos);
1313 		if (!(v.codes & CC_BEHIND) && valid)
1314 			if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
1315 				x = (int) v.screen.xyw.x;
1316 				y = (int) v.screen.xyw.y;
1317 
1318 				if (x >= marking_box.x1 && x <= marking_box.x2 && y >= marking_box.y1 && y <= marking_box.y2) {
1319 					if (ptr->flags & OF_MARKED)
1320 						unmark_object(OBJ_INDEX(ptr));
1321 					else
1322 						mark_object(OBJ_INDEX(ptr));
1323 
1324 					if (ptr->type == OBJ_POINT)
1325 						icon_mode = 1;
1326 				}
1327 			}
1328 
1329 		ptr = GET_NEXT(ptr);
1330 	}
1331 
1332 	if (icon_mode) {
1333 		ptr = GET_FIRST(&obj_used_list);
1334 		while (ptr != END_OF_LIST(&obj_used_list)) {
1335 			if ((ptr->flags & OF_MARKED) && (ptr->type != OBJ_POINT))
1336 				unmark_object(OBJ_INDEX(ptr));
1337 
1338 			ptr = GET_NEXT(ptr);
1339 		}
1340 	}
1341 
1342 	Update_ship = Update_wing = 1;
1343 }
1344 
OnMenuPopupShips(UINT wParam,LONG lParam)1345 LONG CFREDView::OnMenuPopupShips(UINT wParam, LONG lParam)
1346 {
1347 	CMenu	menu;
1348 	CPoint	point;
1349 
1350 	point = * ((CPoint*) lParam);
1351 
1352 	ClientToScreen(&point);
1353 
1354 	menu.LoadMenu(IDR_MENU_SHIP_POPUP);
1355 	menu.GetSubMenu(0)->TrackPopupMenu(
1356 		TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1357 
1358 	return 0L;
1359 }
1360 
OnMenuPopupEdit(UINT wParam,LONG lParam)1361 LONG CFREDView::OnMenuPopupEdit(UINT wParam, LONG lParam)
1362 {
1363 	CMenu	menu;
1364 	CPoint	point;
1365 
1366 	point = * ((CPoint*) lParam);
1367 
1368 	ClientToScreen(&point);
1369 
1370 	menu.LoadMenu(IDR_MENU_EDIT_POPUP);
1371 	menu.GetSubMenu(0)->TrackPopupMenu(
1372 		TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1373 
1374 	return 0L;
1375 }
1376 
1377 int	g_Ships_as_icons = 0;
1378 
OnMiscstuffShowshipsasicons()1379 void CFREDView::OnMiscstuffShowshipsasicons()
1380 {
1381 	Update_window = 1;
1382 	if (g_Ships_as_icons == 0)
1383 		g_Ships_as_icons = 1;
1384 	else
1385 		g_Ships_as_icons = 0;
1386 }
1387 
1388 // right mouse button popup menu stuff
OnContextMenu(CWnd *,CPoint point)1389 void CFREDView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
1390 {
1391 	// make sure window is active
1392 //	GetParentFrame()->ActivateFrame();
1393 
1394 	CMenu menu;
1395 	int	objnum;
1396 	CPoint local = point;
1397 	SCP_list<CJumpNode>::iterator jnp;
1398 
1399 	if (button_down) {
1400 		cancel_drag();
1401 		return;
1402 	}
1403 
1404 	ScreenToClient(&local);
1405 	objnum = select_object(local.x, local.y);
1406 
1407 	if (objnum != -1) {
1408 		set_cur_object_index(objnum);
1409 		if (menu.LoadMenu(IDR_MENU_SHIP_POPUP)) {
1410 			int id = ID_EDITORS_SHIPS;
1411 			CMenu* pPopup = menu.GetSubMenu(0);
1412 
1413 			ASSERT(pPopup != NULL);
1414 			if (Marked > 1)
1415 				pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, ID_EDITORS_SHIPS, "Edit Marked Ships");
1416 			else {
1417 				CString str;
1418 
1419 				if ((Objects[objnum].type == OBJ_START) || (Objects[objnum].type == OBJ_SHIP))
1420 					str.Format("Edit %s", Ships[Objects[objnum].instance].ship_name);
1421 
1422 				else if (Objects[objnum].type == OBJ_JUMP_NODE) {
1423 					id = ID_EDITORS_WAYPOINT;
1424 					for (jnp = Jump_nodes.begin(); jnp != Jump_nodes.end(); ++jnp) {
1425 						if(jnp->GetSCPObject() == &Objects[objnum])
1426 							break;
1427 					}
1428 					str.Format("Edit %s", jnp->GetName());
1429 
1430 				} else if (Objects[objnum].type == OBJ_WAYPOINT) {
1431 					int idx;
1432 					waypoint_list *wp_list = find_waypoint_list_with_instance(Objects[objnum].instance, &idx);
1433 					Assert(wp_list != NULL);
1434 
1435 					id = ID_EDITORS_WAYPOINT;
1436 					str.Format("Edit %s:%d", wp_list->get_name(), idx + 1);
1437 
1438 				} else if (Objects[objnum].type == OBJ_POINT) {
1439 					return;
1440 
1441 				} else {
1442 					Int3();
1443 					str = _T("Unknown");
1444 				}
1445 
1446 				pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, id, str);
1447 			}
1448 
1449 			pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,	point.x, point.y, AfxGetMainWnd()); // use main window for cmds
1450 		}
1451 
1452 	} else {
1453 		if (menu.LoadMenu(IDR_MENU_EDIT_POPUP)) {
1454 			int i;
1455 			CMenu* pPopup = menu.GetSubMenu(0);
1456 			CMenu shipPopup, player_submenu;
1457 			CMenu *species_submenu = new CMenu[Species_info.size()];
1458 			ASSERT(pPopup != NULL);
1459 
1460 			// create a popup menu based on the ship models read in ship.cpp.
1461 			shipPopup.CreatePopupMenu();
1462 			shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_waypoint, "Waypoint");
1463 			shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_start, "Player Start");
1464 			shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_jump_node, "Jump Node");
1465 			for (i=0; i<(int)Species_info.size(); i++) {
1466 				species_submenu[i].CreatePopupMenu();
1467 				shipPopup.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1468 					(UINT) species_submenu[i].m_hMenu, Species_info[i].species_name);
1469 			}
1470 
1471 			for (i=0; i<Num_ship_classes; i++)
1472 				species_submenu[Ship_info[i].species].AppendMenu(MF_STRING |
1473 					MF_ENABLED, SHIP_TYPES + i, Ship_info[i].name);
1474 
1475 			pPopup->AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1476 				(UINT) shipPopup.m_hMenu, "New Object Type");
1477 
1478 			CWnd::DrawMenuBar();	// AppendMenu documentation says to do this.
1479 			pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
1480 		}
1481 	}
1482 }
1483 
OnEditPopupShowShipIcons()1484 void CFREDView::OnEditPopupShowShipIcons()
1485 {
1486 	Show_ship_info = !Show_ship_info;
1487 	theApp.write_ini_file();
1488 	Update_window = 1;
1489 }
1490 
OnUpdateEditPopupShowShipIcons(CCmdUI * pCmdUI)1491 void CFREDView::OnUpdateEditPopupShowShipIcons(CCmdUI* pCmdUI)
1492 {
1493 	pCmdUI->SetCheck(Show_ship_info);
1494 }
1495 
OnEditPopupShowShipModels()1496 void CFREDView::OnEditPopupShowShipModels()
1497 {
1498 	Show_ship_models = !Show_ship_models;
1499 	theApp.write_ini_file();
1500 	Update_window = 1;
1501 }
1502 
OnUpdateEditPopupShowShipModels(CCmdUI * pCmdUI)1503 void CFREDView::OnUpdateEditPopupShowShipModels(CCmdUI* pCmdUI)
1504 {
1505 	pCmdUI->SetCheck(Show_ship_models);
1506 }
1507 
OnEditPopupShowCompass()1508 void CFREDView::OnEditPopupShowCompass()
1509 {
1510 	Show_compass = !Show_compass;
1511 	theApp.write_ini_file();
1512 	Update_window = 1;
1513 }
1514 
OnUpdateEditPopupShowCompass(CCmdUI * pCmdUI)1515 void CFREDView::OnUpdateEditPopupShowCompass(CCmdUI* pCmdUI)
1516 {
1517 	pCmdUI->SetCheck(Show_compass);
1518 }
1519 
1520 // View implementation file
GetView()1521 CFREDView *CFREDView::GetView()
1522 {
1523   CFrameWnd *pFrame = (CFrameWnd *) (AfxGetApp()->m_pMainWnd);
1524 
1525   CView *pView = pFrame->GetActiveView();
1526 
1527   if (!pView)
1528      return NULL;
1529 
1530   // Fail if view is of wrong kind
1531   // (this could occur with splitter windows, or additional
1532   // views on a single document
1533   if (! pView->IsKindOf(RUNTIME_CLASS(CFREDView)))
1534      return NULL;
1535 
1536   return (CFREDView *) pView;
1537 }
1538 
1539 /*void CFREDView::OnShipType0()
1540 {
1541 	cur_model_index = 1;
1542 }
1543 
1544 void CFREDView::OnShipType1()
1545 {
1546 	cur_model_index = 2;
1547 }
1548 
1549 void CFREDView::OnShipType2()
1550 {
1551 	cur_model_index = 3;
1552 }
1553 
1554 void CFREDView::OnShipType3()
1555 {
1556 	cur_model_index = 4;
1557 }
1558 
1559 void CFREDView::OnShipType4()
1560 {
1561 	cur_model_index = 5;
1562 }
1563 
1564 void CFREDView::OnShipType5()
1565 {
1566 	cur_model_index = 6;
1567 }
1568 
1569 void CFREDView::OnUpdateShipType1(CCmdUI* pCmdUI)
1570 {
1571 	pCmdUI->SetCheck(cur_model_index == 2);
1572 }
1573 
1574 void CFREDView::OnUpdateShipType2(CCmdUI* pCmdUI)
1575 {
1576 	pCmdUI->SetCheck(cur_model_index == 3);
1577 }
1578 
1579 void CFREDView::OnUpdateShipType3(CCmdUI* pCmdUI)
1580 {
1581 	pCmdUI->SetCheck(cur_model_index == 4);
1582 }
1583 
1584 void CFREDView::OnUpdateShipType4(CCmdUI* pCmdUI)
1585 {
1586 	pCmdUI->SetCheck(cur_model_index == 5);
1587 }
1588 
1589 void CFREDView::OnUpdateShipType5(CCmdUI* pCmdUI)
1590 {
1591 	pCmdUI->SetCheck(cur_model_index == 6);
1592 }
1593 
1594 
1595 void CFREDView::OnUpdateShipType0(CCmdUI* pCmdUI)
1596 {
1597 	pCmdUI->SetCheck(cur_model_index == 1);
1598 
1599 }
1600 
1601 void CFREDView::OnEditShipType6()
1602 {
1603 	cur_model_index = 7;
1604 
1605 }
1606 
1607 void CFREDView::OnUpdateEditShipType6(CCmdUI* pCmdUI)
1608 {
1609 	pCmdUI->SetCheck(cur_model_index == 7);
1610 } */
1611 
1612 
1613 // following code added by MWA 09/04/96
1614 // Implements messages for popup menu built on the fly.
1615 // not sure how stable the code is, but appears to work for now.
1616 // id's for the menu items are simply the model numbers for
1617 // the ships.  Shouldn't conflict with any other ID_* thingys.
OnCmdMsg(UINT nID,int nCode,void * pExtra,AFX_CMDHANDLERINFO * pHandlerInfo)1618 BOOL CFREDView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
1619 {
1620 	int id = (int) nID;
1621 
1622 	if (!pHandlerInfo) {
1623 		if ((id >= SHIP_TYPES) && (id < SHIP_TYPES + Num_ship_classes + 3)) {
1624 			if (nCode == CN_COMMAND) {
1625 				cur_model_index = id - SHIP_TYPES;
1626 				m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
1627 
1628 			} else if (nCode == CN_UPDATE_COMMAND_UI)	{
1629 				// Update UI element state
1630 				((CCmdUI*) pExtra)->SetCheck(cur_model_index + SHIP_TYPES == id);
1631 				((CCmdUI*) pExtra)->Enable(TRUE);
1632 			}
1633 
1634 			return TRUE;
1635 		}
1636 	}
1637 
1638 	return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
1639 }
1640 
OnMiscStatistics()1641 void CFREDView::OnMiscStatistics()
1642 {
1643 	char buf[2048];
1644 
1645 	sprintf(buf,
1646 		"Number of Objects: %d\n"
1647 		"Number of Ships:   %d\n"
1648 		"Number of Wings:   %d\n",
1649 		Num_objects, ship_get_num_ships(), Num_wings);
1650 
1651 	MessageBox(buf, "FRED Statistics");
1652 }
1653 
OnUpdateChangeViewpointExternal(CCmdUI * pCmdUI)1654 void CFREDView::OnUpdateChangeViewpointExternal(CCmdUI* pCmdUI)
1655 {
1656 	pCmdUI->SetCheck(!viewpoint);
1657 }
1658 
OnChangeViewpointExternal()1659 void CFREDView::OnChangeViewpointExternal()
1660 {
1661 	viewpoint = 0;
1662 	Update_window = 1;
1663 }
1664 
OnUpdateChangeViewpointFollow(CCmdUI * pCmdUI)1665 void CFREDView::OnUpdateChangeViewpointFollow(CCmdUI* pCmdUI)
1666 {
1667 	pCmdUI->SetCheck(viewpoint == 1);
1668 }
1669 
OnChangeViewpointFollow()1670 void CFREDView::OnChangeViewpointFollow()
1671 {
1672 	viewpoint = 1;
1673 	view_obj = cur_object_index;
1674 	Update_window = 1;
1675 }
1676 
OnEditorsGoals()1677 void CFREDView::OnEditorsGoals()
1678 {
1679 	CMissionGoalsDlg dlg;
1680 
1681 	dlg.DoModal();
1682 }
1683 
OnSpeed1()1684 void CFREDView::OnSpeed1()
1685 {
1686 	physics_speed = 1;
1687 	set_physics_controls();
1688 }
1689 
OnSpeed2()1690 void CFREDView::OnSpeed2()
1691 {
1692 	physics_speed = 2;
1693 	set_physics_controls();
1694 }
1695 
OnSpeed3()1696 void CFREDView::OnSpeed3()
1697 {
1698 	physics_speed = 3;
1699 	set_physics_controls();
1700 }
1701 
OnSpeed5()1702 void CFREDView::OnSpeed5()
1703 {
1704 	physics_speed = 5;
1705 	set_physics_controls();
1706 }
1707 
OnSpeed8()1708 void CFREDView::OnSpeed8()
1709 {
1710 	physics_speed = 8;
1711 	set_physics_controls();
1712 }
1713 
OnSpeed10()1714 void CFREDView::OnSpeed10()
1715 {
1716 	physics_speed = 10;
1717 	set_physics_controls();
1718 }
1719 
OnSpeed50()1720 void CFREDView::OnSpeed50()
1721 {
1722 	physics_speed = 50;
1723 	set_physics_controls();
1724 }
1725 
OnSpeed100()1726 void CFREDView::OnSpeed100()
1727 {
1728 	physics_speed = 100;
1729 	set_physics_controls();
1730 }
1731 
OnRot1()1732 void CFREDView::OnRot1()
1733 {
1734 	physics_rot = 2;
1735 	set_physics_controls();
1736 }
1737 
OnRot2()1738 void CFREDView::OnRot2()
1739 {
1740 	physics_rot = 10;
1741 	set_physics_controls();
1742 }
1743 
OnRot3()1744 void CFREDView::OnRot3()
1745 {
1746 	physics_rot = 25;
1747 	set_physics_controls();
1748 }
1749 
OnRot4()1750 void CFREDView::OnRot4()
1751 {
1752 	physics_rot = 50;
1753 	set_physics_controls();
1754 }
1755 
OnRot5()1756 void CFREDView::OnRot5()
1757 {
1758 	physics_rot = 100;
1759 	set_physics_controls();
1760 }
1761 
OnUpdateSpeed1(CCmdUI * pCmdUI)1762 void CFREDView::OnUpdateSpeed1(CCmdUI* pCmdUI)
1763 {
1764 	pCmdUI->SetCheck(physics_speed == 1);
1765 }
1766 
OnUpdateSpeed2(CCmdUI * pCmdUI)1767 void CFREDView::OnUpdateSpeed2(CCmdUI* pCmdUI)
1768 {
1769 	pCmdUI->SetCheck(physics_speed == 2);
1770 }
1771 
OnUpdateSpeed3(CCmdUI * pCmdUI)1772 void CFREDView::OnUpdateSpeed3(CCmdUI* pCmdUI)
1773 {
1774 	pCmdUI->SetCheck(physics_speed == 3);
1775 }
1776 
OnUpdateSpeed5(CCmdUI * pCmdUI)1777 void CFREDView::OnUpdateSpeed5(CCmdUI* pCmdUI)
1778 {
1779 	pCmdUI->SetCheck(physics_speed == 5);
1780 }
1781 
OnUpdateSpeed8(CCmdUI * pCmdUI)1782 void CFREDView::OnUpdateSpeed8(CCmdUI* pCmdUI)
1783 {
1784 	pCmdUI->SetCheck(physics_speed == 8);
1785 }
1786 
OnUpdateSpeed10(CCmdUI * pCmdUI)1787 void CFREDView::OnUpdateSpeed10(CCmdUI* pCmdUI)
1788 {
1789 	pCmdUI->SetCheck(physics_speed == 10);
1790 }
1791 
OnUpdateSpeed50(CCmdUI * pCmdUI)1792 void CFREDView::OnUpdateSpeed50(CCmdUI* pCmdUI)
1793 {
1794 	pCmdUI->SetCheck(physics_speed == 50);
1795 }
1796 
OnUpdateSpeed100(CCmdUI * pCmdUI)1797 void CFREDView::OnUpdateSpeed100(CCmdUI* pCmdUI)
1798 {
1799 	pCmdUI->SetCheck(physics_speed == 100);
1800 }
1801 
OnUpdateRot1(CCmdUI * pCmdUI)1802 void CFREDView::OnUpdateRot1(CCmdUI* pCmdUI)
1803 {
1804 	pCmdUI->SetCheck(physics_rot == 2);
1805 }
1806 
OnUpdateRot2(CCmdUI * pCmdUI)1807 void CFREDView::OnUpdateRot2(CCmdUI* pCmdUI)
1808 {
1809 	pCmdUI->SetCheck(physics_rot == 10);
1810 }
1811 
OnUpdateRot3(CCmdUI * pCmdUI)1812 void CFREDView::OnUpdateRot3(CCmdUI* pCmdUI)
1813 {
1814 	pCmdUI->SetCheck(physics_rot == 25);
1815 }
1816 
OnUpdateRot4(CCmdUI * pCmdUI)1817 void CFREDView::OnUpdateRot4(CCmdUI* pCmdUI)
1818 {
1819 	pCmdUI->SetCheck(physics_rot == 50);
1820 }
1821 
OnUpdateRot5(CCmdUI * pCmdUI)1822 void CFREDView::OnUpdateRot5(CCmdUI* pCmdUI)
1823 {
1824 	pCmdUI->SetCheck(physics_rot == 100);
1825 }
1826 
OnControlModeCamera()1827 void CFREDView::OnControlModeCamera()
1828 {
1829 	Control_mode = 0;
1830 }
1831 
OnUpdateControlModeCamera(CCmdUI * pCmdUI)1832 void CFREDView::OnUpdateControlModeCamera(CCmdUI* pCmdUI)
1833 {
1834 	pCmdUI->SetCheck(!Control_mode);
1835 }
1836 
OnControlModeShip()1837 void CFREDView::OnControlModeShip()
1838 {
1839 	Control_mode = 1;
1840 }
1841 
OnUpdateControlModeShip(CCmdUI * pCmdUI)1842 void CFREDView::OnUpdateControlModeShip(CCmdUI* pCmdUI)
1843 {
1844 	pCmdUI->SetCheck(Control_mode == 1);
1845 }
1846 
OnShowGridPositions()1847 void CFREDView::OnShowGridPositions()
1848 {
1849 	Show_grid_positions = !Show_grid_positions;
1850 	theApp.write_ini_file();
1851 	Update_window = 1;
1852 }
1853 
OnUpdateShowGridPositions(CCmdUI * pCmdUI)1854 void CFREDView::OnUpdateShowGridPositions(CCmdUI* pCmdUI)
1855 {
1856 	pCmdUI->SetCheck(Show_grid_positions);
1857 }
1858 
OnShowCoordinates()1859 void CFREDView::OnShowCoordinates()
1860 {
1861 	Show_coordinates = !Show_coordinates;
1862 	theApp.write_ini_file();
1863 	Update_window = 1;
1864 }
1865 
OnUpdateShowCoordinates(CCmdUI * pCmdUI)1866 void CFREDView::OnUpdateShowCoordinates(CCmdUI* pCmdUI)
1867 {
1868 	pCmdUI->SetCheck(Show_coordinates);
1869 }
1870 
OnSelect()1871 void CFREDView::OnSelect()
1872 {
1873 	Editing_mode = 0;
1874 }
1875 
OnUpdateSelect(CCmdUI * pCmdUI)1876 void CFREDView::OnUpdateSelect(CCmdUI* pCmdUI)
1877 {
1878 	pCmdUI->SetCheck(!Editing_mode);
1879 }
1880 
OnSelectAndMove()1881 void CFREDView::OnSelectAndMove()
1882 {
1883 	Editing_mode = 1;
1884 }
1885 
OnUpdateSelectAndMove(CCmdUI * pCmdUI)1886 void CFREDView::OnUpdateSelectAndMove(CCmdUI* pCmdUI)
1887 {
1888 	pCmdUI->SetCheck(Editing_mode == 1);
1889 }
1890 
OnSelectAndRotate()1891 void CFREDView::OnSelectAndRotate()
1892 {
1893 	Editing_mode = 2;
1894 }
1895 
OnUpdateSelectAndRotate(CCmdUI * pCmdUI)1896 void CFREDView::OnUpdateSelectAndRotate(CCmdUI* pCmdUI)
1897 {
1898 	pCmdUI->SetCheck(Editing_mode == 2);
1899 }
1900 
OnConstrainX()1901 void CFREDView::OnConstrainX()
1902 {
1903 	vm_vec_make(&Constraint, 1.0f, 0.0f, 0.0f);
1904 	vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 1.0f);
1905 	Single_axis_constraint = 1;
1906 }
1907 
OnUpdateConstrainX(CCmdUI * pCmdUI)1908 void CFREDView::OnUpdateConstrainX(CCmdUI* pCmdUI)
1909 {
1910 	pCmdUI->SetRadio(Constraint.xyz.x && !Constraint.xyz.y && !Constraint.xyz.z);
1911 }
1912 
OnConstrainY()1913 void CFREDView::OnConstrainY()
1914 {
1915 	vm_vec_make(&Constraint, 0.0f, 1.0f, 0.0f);
1916 	vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 1.0f);
1917 	Single_axis_constraint = 1;
1918 }
1919 
OnUpdateConstrainY(CCmdUI * pCmdUI)1920 void CFREDView::OnUpdateConstrainY(CCmdUI* pCmdUI)
1921 {
1922 	pCmdUI->SetRadio(!Constraint.xyz.x && Constraint.xyz.y && !Constraint.xyz.z);
1923 }
1924 
OnConstrainZ()1925 void CFREDView::OnConstrainZ()
1926 {
1927 	vm_vec_make(&Constraint, 0.0f, 0.0f, 1.0f);
1928 	vm_vec_make(&Anticonstraint, 1.0f, 1.0f, 0.0f);
1929 	Single_axis_constraint = 1;
1930 }
1931 
OnUpdateConstrainZ(CCmdUI * pCmdUI)1932 void CFREDView::OnUpdateConstrainZ(CCmdUI* pCmdUI)
1933 {
1934 	pCmdUI->SetRadio(!Constraint.xyz.x && !Constraint.xyz.y && Constraint.xyz.z);
1935 }
1936 
OnConstrainXz()1937 void CFREDView::OnConstrainXz()
1938 {
1939 	vm_vec_make(&Constraint, 1.0f, 0.0f, 1.0f);
1940 	vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 0.0f);
1941 	Single_axis_constraint = 0;
1942 }
1943 
OnUpdateConstrainXz(CCmdUI * pCmdUI)1944 void CFREDView::OnUpdateConstrainXz(CCmdUI* pCmdUI)
1945 {
1946 	pCmdUI->SetRadio(Constraint.xyz.x && !Constraint.xyz.y && Constraint.xyz.z);
1947 }
1948 
OnConstrainXy()1949 void CFREDView::OnConstrainXy()
1950 {
1951 	vm_vec_make(&Constraint, 1.0f, 1.0f, 0.0f);
1952 	vm_vec_make(&Anticonstraint, 0.0f, 0.0f, 1.0f);
1953 	Single_axis_constraint = 0;
1954 }
1955 
OnUpdateConstrainXy(CCmdUI * pCmdUI)1956 void CFREDView::OnUpdateConstrainXy(CCmdUI* pCmdUI)
1957 {
1958 	pCmdUI->SetRadio(Constraint.xyz.x && Constraint.xyz.y && !Constraint.xyz.z);
1959 }
1960 
OnConstrainYz()1961 void CFREDView::OnConstrainYz()
1962 {
1963 	vm_vec_make(&Constraint, 0.0f, 1.0f, 1.0f);
1964 	vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 0.0f);
1965 	Single_axis_constraint = 0;
1966 }
1967 
OnUpdateConstrainYz(CCmdUI * pCmdUI)1968 void CFREDView::OnUpdateConstrainYz(CCmdUI* pCmdUI)
1969 {
1970 	pCmdUI->SetRadio(!Constraint.xyz.x && Constraint.xyz.y && Constraint.xyz.z);
1971 }
1972 
OnSelectionLock()1973 void CFREDView::OnSelectionLock()
1974 {
1975 	Selection_lock = !Selection_lock;
1976 }
1977 
OnUpdateSelectionLock(CCmdUI * pCmdUI)1978 void CFREDView::OnUpdateSelectionLock(CCmdUI* pCmdUI)
1979 {
1980 	pCmdUI->SetCheck(Selection_lock);
1981 }
1982 
OnLButtonDblClk(UINT nFlags,CPoint point)1983 void CFREDView::OnLButtonDblClk(UINT nFlags, CPoint point)
1984 {
1985 	CView::OnLButtonDblClk(nFlags, point);
1986 	if (Cursor_over != -1) {
1987 		switch (Objects[Cursor_over].type) {
1988 			case OBJ_SHIP:
1989 			case OBJ_START:
1990 				OnEditorsShips();
1991 				break;
1992 
1993 			case OBJ_WAYPOINT:
1994 			case OBJ_JUMP_NODE:
1995 				OnEditorsWaypoint();
1996 				break;
1997 		}
1998 
1999 	} else if (Briefing_dialog)
2000 		Fixed_briefing_size = !Fixed_briefing_size;
2001 }
2002 
OnDoubleFineGridlines()2003 void CFREDView::OnDoubleFineGridlines()
2004 {
2005 	double_fine_gridlines = !double_fine_gridlines;
2006 	maybe_create_new_grid(The_grid, &eye_pos, &eye_orient, 1);
2007 	theApp.write_ini_file();
2008 	Update_window = 1;
2009 }
2010 
OnUpdateDoubleFineGridlines(CCmdUI * pCmdUI)2011 void CFREDView::OnUpdateDoubleFineGridlines(CCmdUI* pCmdUI)
2012 {
2013 	pCmdUI->SetCheck(double_fine_gridlines);
2014 }
2015 
OnShowDistances()2016 void CFREDView::OnShowDistances()
2017 {
2018 	Show_distances = !Show_distances;
2019 	theApp.write_ini_file();
2020 	Update_window = 1;
2021 }
2022 
OnUpdateShowDistances(CCmdUI * pCmdUI)2023 void CFREDView::OnUpdateShowDistances(CCmdUI* pCmdUI)
2024 {
2025 	pCmdUI->SetCheck(Show_distances);
2026 }
2027 
OnUniversalHeading()2028 void CFREDView::OnUniversalHeading()
2029 {
2030 	Universal_heading = !Universal_heading;
2031 }
2032 
OnUpdateUniversalHeading(CCmdUI * pCmdUI)2033 void CFREDView::OnUpdateUniversalHeading(CCmdUI* pCmdUI)
2034 {
2035 	pCmdUI->SetCheck(Universal_heading);
2036 }
2037 
OnFlyingControls()2038 void CFREDView::OnFlyingControls()
2039 {
2040 	Flying_controls_mode = !Flying_controls_mode;
2041 }
2042 
OnUpdateFlyingControls(CCmdUI * pCmdUI)2043 void CFREDView::OnUpdateFlyingControls(CCmdUI* pCmdUI)
2044 {
2045 	pCmdUI->SetCheck(Flying_controls_mode);
2046 }
2047 
OnRotateLocally()2048 void CFREDView::OnRotateLocally()
2049 {
2050 	Group_rotate = !Group_rotate;
2051 }
2052 
OnUpdateRotateLocally(CCmdUI * pCmdUI)2053 void CFREDView::OnUpdateRotateLocally(CCmdUI* pCmdUI)
2054 {
2055 	pCmdUI->SetCheck(!Group_rotate);
2056 }
2057 
OnSelectList()2058 void CFREDView::OnSelectList()
2059 {
2060 	ship_select dlg;
2061 
2062 	dlg.DoModal();
2063 }
2064 
2065 // position camera to view all objects on the screen at once.  Doesn't change orientation.
view_universe(int just_marked)2066 void view_universe(int just_marked)
2067 {
2068 	int i, max = 0, flags[MAX_OBJECTS];
2069 	float dist, largest = 20.0f;
2070 	vec3d center, p1, p2;		// center of all the objects collectively
2071 	vertex v;
2072 	object *ptr;
2073 
2074 	for (i=0; i<MAX_OBJECTS; i++)
2075 		flags[i] = 0;
2076 
2077 	if (just_marked)
2078 		ptr = &Objects[cur_object_index];
2079 	else
2080 		ptr = GET_FIRST(&obj_used_list);
2081 
2082 	p1.xyz.x = p2.xyz.x = ptr->pos.xyz.x;
2083 	p1.xyz.y = p2.xyz.y = ptr->pos.xyz.y;
2084 	p1.xyz.z = p2.xyz.z = ptr->pos.xyz.z;
2085 
2086 	ptr = GET_FIRST(&obj_used_list);
2087 	while (ptr != END_OF_LIST(&obj_used_list)) {
2088 		if (!just_marked || (ptr->flags & OF_MARKED)) {
2089 			center = ptr->pos;
2090 			if (center.xyz.x < p1.xyz.x)
2091 				p1.xyz.x = center.xyz.x;
2092 			if (center.xyz.x > p2.xyz.x)
2093 				p2.xyz.x = center.xyz.x;
2094 			if (center.xyz.y < p1.xyz.y)
2095 				p1.xyz.y = center.xyz.y;
2096 			if (center.xyz.y > p2.xyz.y)
2097 				p2.xyz.y = center.xyz.y;
2098 			if (center.xyz.z < p1.xyz.z)
2099 				p1.xyz.z = center.xyz.z;
2100 			if (center.xyz.z > p2.xyz.z)
2101 				p2.xyz.z = center.xyz.z;
2102 		}
2103 
2104 		ptr = GET_NEXT(ptr);
2105 	}
2106 
2107 	vm_vec_avg(&center, &p1, &p2);
2108 	ptr = GET_FIRST(&obj_used_list);
2109 	while (ptr != END_OF_LIST(&obj_used_list)) {
2110 		if (!just_marked || (ptr->flags & OF_MARKED)) {
2111 			dist = vm_vec_dist_squared(&center, &ptr->pos);
2112 			if (dist > largest)
2113 				largest = dist;
2114 
2115 			flags[OBJ_INDEX(ptr)] = 1;  // flag object as needing on-screen check
2116 			if (OBJ_INDEX(ptr) > max)
2117 				max = OBJ_INDEX(ptr);
2118 		}
2119 
2120 		ptr = GET_NEXT(ptr);
2121 	}
2122 
2123 	dist = fl_sqrt(largest) + 1.0f;
2124 	vm_vec_scale_add(&view_pos, &center, &view_orient.vec.fvec, -dist);
2125 	g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2126 
2127 	ptr = GET_FIRST(&obj_used_list);
2128 	while (ptr != END_OF_LIST(&obj_used_list)) {
2129 		if (!just_marked || (ptr->flags & OF_MARKED)) {
2130 			g3_rotate_vertex(&v, &ptr->pos);
2131 			Assert(!(v.codes & CC_BEHIND));
2132 			if (g3_project_vertex(&v) & PF_OVERFLOW)
2133 				Int3();
2134 
2135 			while (v.codes & CC_OFF) {  // is point off screen?
2136 				dist += 5.0f;  // zoom out a little and check again.
2137 				vm_vec_scale_add(&view_pos, &center, &view_orient.vec.fvec, -dist);
2138 				g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2139 				g3_rotate_vertex(&v, &ptr->pos);
2140 				if (g3_project_vertex(&v) & PF_OVERFLOW)
2141 					Int3();
2142 			}
2143 		}
2144 
2145 		ptr = GET_NEXT(ptr);
2146 	}
2147 
2148 	dist *= 1.1f;
2149 	vm_vec_scale_add(&view_pos, &center, &view_orient.vec.fvec, -dist);
2150 	g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2151 	Update_window = 1;
2152 }
2153 
cycle_constraint()2154 void CFREDView::cycle_constraint()
2155 {
2156 	if (Single_axis_constraint) {
2157 		if (Constraint.xyz.x)
2158 			OnConstrainY();
2159 		else if (Constraint.xyz.y)
2160 			OnConstrainZ();
2161 		else if (Constraint.xyz.z)
2162 			OnConstrainXz();
2163 
2164 	} else {
2165 		if (!Constraint.xyz.x)
2166 			OnConstrainXy();
2167 		else if (!Constraint.xyz.y)
2168 			OnConstrainYz();
2169 		else if (!Constraint.xyz.z)
2170 			OnConstrainX();
2171 	}
2172 }
2173 
OnZoomExtents()2174 void CFREDView::OnZoomExtents()
2175 {
2176 	view_universe();
2177 }
2178 
OnZoomSelected()2179 void CFREDView::OnZoomSelected()
2180 {
2181 	if (query_valid_object()) {
2182 		if (Marked > 1)
2183 			view_universe(1);
2184 		else
2185 			vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.vec.fvec, Objects[cur_object_index].radius * -3.0f);
2186 	}
2187 
2188 	Update_window = 1;
2189 }
2190 
OnUpdateZoomSelected(CCmdUI * pCmdUI)2191 void CFREDView::OnUpdateZoomSelected(CCmdUI* pCmdUI)
2192 {
2193 	pCmdUI->Enable(query_valid_object());
2194 }
2195 
OnFormWing()2196 void CFREDView::OnFormWing()
2197 {
2198 	object *ptr = GET_FIRST(&obj_used_list);
2199 	bool found = false;
2200 	while (ptr != END_OF_LIST(&obj_used_list)) {
2201 		if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags & OF_MARKED)) {
2202 			if(Ships[ptr->instance].flags & SF_REINFORCEMENT) {
2203 				found = true;
2204 				break;
2205 			}
2206 		}
2207 
2208 		ptr = GET_NEXT(ptr);
2209 	}
2210 
2211 	if(found) {
2212 		int ok = MessageBox("Some of the ships you selected to create a wing are marked as reinforcements. Press Ok to clear the flag on all selected ships. Press Cancel to not create the wing.", "Reinforcement conflict", MB_ICONEXCLAMATION | MB_OKCANCEL);
2213 		if(ok == IDOK) {
2214 			ptr = GET_FIRST(&obj_used_list);
2215 			while (ptr != END_OF_LIST(&obj_used_list)) {
2216 				if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags & OF_MARKED)) {
2217 					set_reinforcement(Ships[ptr->instance].ship_name, 0);
2218 				}
2219 
2220 			ptr = GET_NEXT(ptr);
2221 			}
2222 		} else {
2223 			return;
2224 		}
2225 	}
2226 
2227 	if (!create_wing())
2228 		FREDDoc_ptr->autosave("form wing");
2229 }
2230 
OnUpdateFormWing(CCmdUI * pCmdUI)2231 void CFREDView::OnUpdateFormWing(CCmdUI* pCmdUI)
2232 {
2233 	int count = 0;
2234 	object *ptr;
2235 
2236 	if (query_valid_object()) {
2237 		ptr = GET_FIRST(&obj_used_list);
2238 		while (ptr != END_OF_LIST(&obj_used_list)) {
2239 			if (ptr->flags & OF_MARKED) {
2240 				if (ptr->type == OBJ_SHIP)
2241 				{
2242 					int ship_type = ship_query_general_type(ptr->instance);
2243 					if(ship_type > -1 && (Ship_types[ship_type].ai_bools & STI_AI_CAN_FORM_WING))
2244 					{
2245 						count++;
2246 					}
2247 				}
2248 
2249 				if (ptr->type == OBJ_START)
2250 					count++;
2251 			}
2252 
2253 			ptr = GET_NEXT(ptr);
2254 		}
2255 	}
2256 
2257 	pCmdUI->Enable(count > 0);
2258 }
2259 
query_single_wing_marked()2260 int query_single_wing_marked()
2261 {
2262 	int i, obj;
2263 
2264 	if (!query_valid_object())
2265 		return 0;
2266 
2267 	if (cur_wing == -1)
2268 		return 0;
2269 
2270 	i = Wings[cur_wing].wave_count;
2271 	if (Marked != i)  // does marked object count match number of ships in wing?
2272 		return 0;
2273 
2274 	while (i--) {
2275 		obj = wing_objects[cur_wing][i];
2276 		if ((Objects[obj].type != OBJ_SHIP) && (Objects[obj].type != OBJ_START))
2277 			Error(LOCATION, "Invalid objects detected in wing \"%s\"", Wings[cur_wing].name);
2278 
2279 //		if (Ships[Objects[obj].instance].wingnum != cur_wing)
2280 //			return 0;
2281 		Assert(Ships[Objects[obj].instance].wingnum == cur_wing);
2282 		if (!(Objects[obj].flags & OF_MARKED))  // ensure all ships in wing.are marked
2283 			return 0;
2284 	}
2285 
2286 	return 1;
2287 }
2288 
OnDisbandWing()2289 void CFREDView::OnDisbandWing()
2290 {
2291 	if (query_single_wing_marked()) {
2292 		remove_wing(cur_wing);
2293 		FREDDoc_ptr->autosave("wing disband");
2294 
2295 	} else
2296 		MessageBox("One and only one wing must be selected for this operation");
2297 }
2298 
OnUpdateDisbandWing(CCmdUI * pCmdUI)2299 void CFREDView::OnUpdateDisbandWing(CCmdUI* pCmdUI)
2300 {
2301 	pCmdUI->Enable(query_single_wing_marked());
2302 }
2303 
OnShowHorizon()2304 void CFREDView::OnShowHorizon()
2305 {
2306 	Show_horizon = !Show_horizon;
2307 	theApp.write_ini_file();
2308 	Update_window = 1;
2309 }
2310 
OnUpdateShowHorizon(CCmdUI * pCmdUI)2311 void CFREDView::OnUpdateShowHorizon(CCmdUI* pCmdUI)
2312 {
2313 	pCmdUI->SetCheck(Show_horizon);
2314 }
2315 
OnEditorsWing()2316 void CFREDView::OnEditorsWing()
2317 {
2318 	int adjust = 0;
2319 
2320 	Assert(Wing_editor_dialog.GetSafeHwnd());
2321 	if (!Show_sexp_help)
2322 		adjust = -SEXP_HELP_BOX_SIZE;
2323 
2324 	if (!theApp.init_window(&Wing_wnd_data, &Wing_editor_dialog, adjust))
2325 		return;
2326 
2327 	Wing_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
2328 		SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2329 	Wing_editor_dialog.ShowWindow(SW_RESTORE);
2330 }
2331 
OnEditorsPlayer()2332 void CFREDView::OnEditorsPlayer()
2333 {
2334 	player_start_editor dlg;
2335 
2336 	dlg.DoModal();
2337 }
2338 
OnEditorsOrient()2339 void CFREDView::OnEditorsOrient()
2340 {
2341 	orient_editor dlg;
2342 
2343 	dlg.DoModal();
2344 }
2345 
OnEditorsEvents()2346 void CFREDView::OnEditorsEvents()
2347 {
2348 	if (Message_editor_dlg) {
2349 		MessageBox("You must close the message editor before opening the event editor");
2350 		return;
2351 	}
2352 
2353 	if (!Event_editor_dlg) {
2354 		Event_editor_dlg = new event_editor;
2355 		Event_editor_dlg->Create(event_editor::IDD);
2356 	}
2357 
2358 	Event_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2359 	Event_editor_dlg->ShowWindow(SW_RESTORE);
2360 }
2361 
OnUpdateEditorsOrient(CCmdUI * pCmdUI)2362 void CFREDView::OnUpdateEditorsOrient(CCmdUI* pCmdUI)
2363 {
2364 	pCmdUI->Enable(query_valid_object());
2365 }
2366 
OnEditorsMessage()2367 void CFREDView::OnEditorsMessage()
2368 {
2369 	if (Event_editor_dlg) {
2370 		MessageBox("You must close the event editor before opening the message editor");
2371 		return;
2372 	}
2373 
2374 	if (!Message_editor_dlg) {
2375 		Message_editor_dlg = new CMessageEditorDlg;
2376 		Message_editor_dlg->Create(CMessageEditorDlg::IDD);
2377 	}
2378 
2379 	Message_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2380 	Message_editor_dlg->ShowWindow(SW_RESTORE);
2381 }
2382 
OnEditorsStarfield()2383 void CFREDView::OnEditorsStarfield()
2384 {
2385 	starfield_editor dlg;
2386 
2387 	dlg.DoModal();
2388 }
2389 
place_background_bitmap(vec3d v)2390 void CFREDView::place_background_bitmap(vec3d v)
2391 {
2392 }
2393 
OnEditorsBgBitmaps()2394 void CFREDView::OnEditorsBgBitmaps()
2395 {
2396 	if (!Bg_bitmap_dialog) {
2397 		Bg_bitmap_dialog = new bg_bitmap_dlg;
2398 		Bg_bitmap_dialog->create();
2399 	}
2400 
2401 	Bg_bitmap_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
2402 		SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2403 	Bg_bitmap_dialog->ShowWindow(SW_RESTORE);
2404 }
2405 
OnEditorsReinforcement()2406 void CFREDView::OnEditorsReinforcement()
2407 {
2408 	reinforcement_editor_dlg dlg;
2409 
2410 	dlg.DoModal();
2411 }
2412 
OnErrorChecker()2413 void CFREDView::OnErrorChecker()
2414 {
2415 	int z;
2416 
2417 	z = global_error_check();
2418 	if (!z)
2419 		MessageBox("No errors were detected in this mission", "Woohoo!");
2420 
2421 	for (z=0; z<obj_count; z++)
2422 		if (flags[z])
2423 			delete [] names[z];
2424 
2425 	obj_count = 0;
2426 }
2427 
global_error_check()2428 int CFREDView::global_error_check()
2429 {
2430 	char buf[256], *str;
2431 	int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
2432 	object *ptr;
2433 	brief_stage *sp;
2434 	int starting_orders;
2435 
2436 	g_err = multi = 0;
2437 	if ( The_mission.game_type & MISSION_TYPE_MULTI )
2438 		multi = 1;
2439 
2440 //	if (!stricmp(The_mission.name, "Untitled"))
2441 //		if (error("You haven't given this mission a title yet.\nThis is done from the Mission Specs Editor (Shift-N)."))
2442 //			return 1;
2443 
2444 	// cycle though all the objects and verify every possible aspect of them
2445 	obj_count = t = 0;
2446 	ptr = GET_FIRST(&obj_used_list);
2447 	while (ptr != END_OF_LIST(&obj_used_list)) {
2448 		names[obj_count] = NULL;
2449 		flags[obj_count] = 0;
2450 		i = ptr->instance;
2451 		if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
2452 			if (i < 0 || i >= MAX_SHIPS){
2453 				return internal_error("An object has an illegal ship index");
2454 			}
2455 
2456 			z = Ships[i].ship_info_index;
2457 			if ((z < 0) || (z >= Num_ship_classes)){
2458 				return internal_error("A ship has an illegal class");
2459 			}
2460 
2461 			if (ptr->type == OBJ_START) {
2462 				t++;
2463 				if (!(Ship_info[z].flags & SIF_PLAYER_SHIP)) {
2464 					ptr->type = OBJ_SHIP;
2465 					Player_starts--;
2466 					t--;
2467 					if (error("Invalid ship type for a player.  Ship has been reset to non-player ship.")){
2468 						return 1;
2469 					}
2470 				}
2471 
2472 				for (n=count=0; n<MAX_SHIP_PRIMARY_BANKS; n++){
2473 					if (Ships[i].weapons.primary_bank_weapons[n] >= 0){
2474 						count++;
2475 					}
2476 				}
2477 
2478 				if (!count){
2479 					if (error("Player \"%s\" has no primary weapons.  Should have at least 1", Ships[i].ship_name)){
2480 						return 1;
2481 					}
2482 				}
2483 
2484 				for (n=count=0; n<MAX_SHIP_SECONDARY_BANKS; n++){
2485 					if (Ships[i].weapons.secondary_bank_weapons[n] >= 0){
2486 						count++;
2487 					}
2488 				}
2489 			}
2490 
2491 			if (Ships[i].objnum != OBJ_INDEX(ptr)){
2492 				return internal_error("Object/ship references are corrupt");
2493 			}
2494 
2495 			names[obj_count] = Ships[i].ship_name;
2496 			wing = Ships[i].wingnum;
2497 			if (wing >= 0) {  // ship is part of a wing, so check this
2498 				if (wing < 0 || wing >= MAX_WINGS){  // completely out of range?
2499 					return internal_error("A ship has an illegal wing index");
2500 				}
2501 
2502 				j = Wings[wing].wave_count;
2503 				if (!j){
2504 					return internal_error("A ship is in a non-existent wing");
2505 				}
2506 
2507 				if (j < 0 || j > MAX_SHIPS_PER_WING){
2508 					return internal_error("Invalid number of ships in wing \"%s\"", Wings[z].name);
2509 				}
2510 
2511 				while (j--){
2512 					if (wing_objects[wing][j] == OBJ_INDEX(ptr)){  // look for object in wing's table
2513 						break;
2514 					}
2515 				}
2516 
2517 				if (j < 0){
2518 					return internal_error("Ship/wing references are corrupt");
2519 				}
2520 
2521 				// wing squad logo check - Goober5000
2522 				if (strlen(Wings[wing].wing_squad_filename) > 0) //-V805
2523 				{
2524 					if (The_mission.game_type & MISSION_TYPE_MULTI)
2525 					{
2526 						if (error("Wing squad logos are not displayed in multiplayer games."))
2527 						{
2528 							return 1;
2529 						}
2530 					}
2531 					else
2532 					{
2533 						if (ptr->type == OBJ_START)
2534 						{
2535 							if (error("A squad logo was assigned to the player's wing.  The player's squad logo will be displayed instead of the wing squad logo on ships in this wing."))
2536 							{
2537 								return 1;
2538 							}
2539 						}
2540 					}
2541 				}
2542 			}
2543 
2544 			if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (Ships[i].hotkey >= 0) ){
2545 				if (error("Ship flagged as \"destroy before mission start\" has a hotkey assignment")){
2546 					return 1;
2547 				}
2548 			}
2549 
2550 			if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (ptr->type == OBJ_START) ){
2551 				if (error("Player start flagged as \"destroy before mission start\"")){
2552 					return 1;
2553 				}
2554 			}
2555 		} else if (ptr->type == OBJ_WAYPOINT) {
2556 			int waypoint_num;
2557 			waypoint_list *wp_list = find_waypoint_list_with_instance(i, &waypoint_num);
2558 
2559 			if (wp_list == NULL) {
2560 				return internal_error("Object references an illegal waypoint path number");
2561 			}
2562 
2563 			if (waypoint_num < 0 || (uint) waypoint_num >= wp_list->get_waypoints().size()) {
2564 				return internal_error("Object references an illegal waypoint number in path");
2565 			}
2566 
2567 			sprintf(buf, "%s:%d", wp_list->get_name(), waypoint_num + 1);
2568 			names[obj_count] = new char[strlen(buf) + 1];
2569 			strcpy(names[obj_count], buf);
2570 			flags[obj_count] = 1;
2571 		} else if (ptr->type == OBJ_POINT) {
2572 			if (!Briefing_dialog){
2573 				return internal_error("Briefing icon detected when not in briefing edit mode");
2574 			}
2575 			//Shouldn't be needed anymore.
2576 			//If we really do need it, call me and I'll write a is_valid function for jumpnodes -WMC
2577 		}
2578 		else if (ptr->type == OBJ_JUMP_NODE)
2579 		{
2580 			//nothing needs to be done here, we just need to make sure the else doesn't occur
2581 		}
2582 		else {
2583 			return internal_error("An unknown object type (%d) was detected", ptr->type);
2584 		}
2585 
2586 		for (i=0; i<obj_count; i++){
2587 			if (names[i] && names[obj_count]){
2588 				if (!stricmp(names[i], names[obj_count])){
2589 					return internal_error("Duplicate object names (%s)", names[i]);
2590 				}
2591 			}
2592 		}
2593 
2594 		obj_count++;
2595 		ptr = GET_NEXT(ptr);
2596 	}
2597 
2598 	if (t != Player_starts){
2599 		return internal_error("Total number of player ships is incorrect");
2600 	}
2601 
2602 	if (obj_count != Num_objects){
2603 		return internal_error("Num_objects is incorrect");
2604 	}
2605 
2606 	count = 0;
2607 	for (i=0; i<MAX_SHIPS; i++) {
2608 		if (Ships[i].objnum >= 0) {  // is ship being used?
2609 			count++;
2610 			if (!query_valid_object(Ships[i].objnum)){
2611 				return internal_error("Ship uses an unused object");
2612 			}
2613 
2614 			z = Objects[Ships[i].objnum].type;
2615 			if ((z != OBJ_SHIP) && (z != OBJ_START)){
2616 				return internal_error("Object should be a ship, but isn't");
2617 			}
2618 
2619 			if (fred_check_sexp(Ships[i].arrival_cue, OPR_BOOL, "arrival cue of ship \"%s\"", Ships[i].ship_name)){
2620 				return -1;
2621 			}
2622 
2623 			if (fred_check_sexp(Ships[i].departure_cue, OPR_BOOL, "departure cue of ship \"%s\"", Ships[i].ship_name)){
2624 				return -1;
2625 			}
2626 
2627 			if (Ships[i].arrival_location != ARRIVE_AT_LOCATION) {
2628 				if (Ships[i].arrival_anchor < 0){
2629 					if (error("Ship \"%s\" requires a valid arrival target", Ships[i].ship_name)){
2630 						return 1;
2631 					}
2632 				}
2633 			}
2634 
2635 			if (Ships[i].departure_location != DEPART_AT_LOCATION) {
2636 				if (Ships[i].departure_anchor < 0){
2637 					if (error("Ship \"%s\" requires a valid departure target", Ships[i].ship_name)){
2638 						return 1;
2639 					}
2640 				}
2641 			}
2642 
2643 			ai = Ships[i].ai_index;
2644 			if (ai < 0 || ai >= MAX_AI_INFO){
2645 				return internal_error("AI index out of range for ship \"%s\"", Ships[i].ship_name);
2646 			}
2647 
2648 			if (Ai_info[ai].shipnum != i){
2649 				return internal_error("AI/ship references are corrupt");
2650 			}
2651 
2652 			if ((str = error_check_initial_orders(Ai_info[ai].goals, i, -1))>0) {
2653 				if (*str == '*')
2654 					return internal_error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str + 1);
2655 				else if (*str == '!')
2656 					return 1;
2657 				else if (error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str))
2658 					return 1;
2659 			}
2660 
2661 
2662 			for (dock_instance *dock_ptr = Objects[Ships[i].objnum].dock_list; dock_ptr != NULL; dock_ptr = dock_ptr->next)
2663 			{
2664 				obj = OBJ_INDEX(dock_ptr->docked_objp);
2665 
2666 				if (!query_valid_object(obj)){
2667 					return internal_error("Ship \"%s\" initially docked with non-existant ship", Ships[i].ship_name);
2668 				}
2669 
2670 					if (Objects[obj].type != OBJ_SHIP && Objects[obj].type != OBJ_START){
2671 						return internal_error("Ship \"%s\" initially docked with non-ship object", Ships[i].ship_name);
2672 					}
2673 
2674 					ship = get_ship_from_obj(obj);
2675 					if (!ship_docking_valid(i, ship) && !ship_docking_valid(ship, i)){
2676 						return internal_error("Docking illegal between \"%s\" and \"%s\" (initially docked)", Ships[i].ship_name, Ships[ship].ship_name);
2677 					}
2678 
2679 				z = get_docking_list(Ship_info[Ships[i].ship_info_index].model_num);
2680 				point = dock_ptr->dockpoint_used;
2681 				if (point < 0 || point >= z){
2682 					internal_error("Invalid docker point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
2683 				}
2684 
2685 				z = get_docking_list(Ship_info[Ships[ship].ship_info_index].model_num);
2686 				point = dock_find_dockpoint_used_by_object(dock_ptr->docked_objp, &Objects[Ships[i].objnum]);
2687 				if (point < 0 || point >= z){
2688 					internal_error("Invalid dockee point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
2689 				}
2690 			}
2691 		}
2692 	}
2693 
2694 	if (count != ship_get_num_ships()){
2695 		return internal_error("num_ships is incorrect");
2696 	}
2697 
2698 	count = 0;
2699 	for (i=0; i<MAX_WINGS; i++) {
2700 		team = -1;
2701 		j = Wings[i].wave_count;
2702 		if (j) {  // is wing being used?
2703 			count++;
2704 			if (j < 0 || j > MAX_SHIPS_PER_WING){
2705 				return internal_error("Invalid number of ships in wing \"%s\"", Wings[i].name);
2706 			}
2707 
2708 			while (j--) {
2709 				obj = wing_objects[i][j];
2710 				if (obj < 0 || obj >= MAX_OBJECTS){
2711 					return internal_error("Wing_objects has an illegal object index");
2712 				}
2713 
2714 				if (!query_valid_object(obj)){
2715 					return internal_error("Wing_objects references an unused object");
2716 				}
2717 
2718 // Now, at this point, we can assume several things.  We have a valid object because
2719 // we passed query_valid_object(), and all valid objects were already checked above,
2720 // so this object has valid information, such as the instance.
2721 
2722 				if ((Objects[obj].type == OBJ_SHIP) || (Objects[obj].type == OBJ_START)) {
2723 					ship = Objects[obj].instance;
2724 					wing_bash_ship_name(buf, Wings[i].name, j + 1);
2725 					if (stricmp(buf, Ships[ship].ship_name)){
2726 						return internal_error("Ship \"%s\" in wing should be called \"%s\"", Ships[ship].ship_name, buf);
2727 					}
2728 
2729 					int ship_type = ship_query_general_type(ship);
2730 					if(ship_type < 0 || !(Ship_types[ship_type].ai_bools & STI_AI_CAN_FORM_WING))
2731 					{
2732 							if (error("Ship \"%s\" is an illegal type to be in a wing", Ships[ship].ship_name)){
2733 								return 1;
2734 							}
2735 					}
2736 				} else {
2737 					return internal_error("Wing_objects of \"%s\" references an illegal object type", Wings[i].name);
2738 				}
2739 
2740 				if (Ships[ship].wingnum != i){
2741 					return internal_error("Wing/ship references are corrupt");
2742 				}
2743 
2744 				if (ship != Wings[i].ship_index[j]){
2745 					return internal_error("Ship/wing references are corrupt");
2746 				}
2747 
2748 				if (team < 0){
2749 					team = Ships[ship].team;
2750 				} else if (team != Ships[ship].team && team < 999){
2751 					if (error("ship teams mixed within same wing (\"%s\")", Wings[i].name)){
2752 						return 1;
2753 					}
2754 				}
2755 			}
2756 
2757 			if ((Wings[i].special_ship < 0) || (Wings[i].special_ship >= Wings[i].wave_count)){
2758 				return internal_error("Special ship out of range for \"%s\"", Wings[i].name);
2759 			}
2760 
2761 			if (Wings[i].num_waves < 0){
2762 				return internal_error("Number of waves for \"%s\" is negative", Wings[i].name);
2763 			}
2764 
2765 			if ((Wings[i].threshold < 0) || (Wings[i].threshold >= Wings[i].wave_count)){
2766 				return internal_error("Threshold for \"%s\" is invalid", Wings[i].name);
2767 			}
2768 
2769 			if (Wings[i].threshold + Wings[i].wave_count > MAX_SHIPS_PER_WING) {
2770 				Wings[i].threshold = MAX_SHIPS_PER_WING - Wings[i].wave_count;
2771 				if(error("Threshold for wing \"%s\" is higher than allowed.  Reset to %d", Wings[i].name, Wings[i].threshold)){
2772 					return 1;
2773 				}
2774 			}
2775 
2776 			for (j=0; j<obj_count; j++){
2777 				if (names[j]){
2778 					if (!stricmp(names[j], Wings[i].name)){
2779 						return internal_error("Wing name is also used by an object (%s)", names[j]);
2780 					}
2781 				}
2782 			}
2783 
2784 			if(fred_check_sexp(Wings[i].arrival_cue, OPR_BOOL, "arrival cue of wing \"%s\"", Wings[i].name)){
2785 				return -1;
2786 			}
2787 
2788 			if(fred_check_sexp(Wings[i].departure_cue, OPR_BOOL, "departure cue of wing \"%s\"", Wings[i].name)){
2789 				return -1;
2790 			}
2791 
2792 			if (Wings[i].arrival_location != ARRIVE_AT_LOCATION) {
2793 				if (Wings[i].arrival_anchor < 0)
2794 					if (error("Wing \"%s\" requires a valid arrival target", Wings[i].name))
2795 						return 1;
2796 			}
2797 
2798 			if (Wings[i].departure_location != DEPART_AT_LOCATION) {
2799 				if (Wings[i].departure_anchor < 0)
2800 					if (error("Wing \"%s\" requires a valid departure target", Wings[i].name))
2801 						return 1;
2802 			}
2803 
2804 			if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i))>0) {
2805 				if (*str == '*')
2806 					return internal_error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str + 1);
2807 				else if (*str == '!')
2808 					return 1;
2809 				else if (error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str))
2810 					return 1;
2811 			}
2812 
2813 		}
2814 	}
2815 
2816 	if (count != Num_wings){
2817 		return internal_error("Num_wings is incorrect");
2818 	}
2819 
2820 	SCP_list<waypoint_list>::iterator ii;
2821 	for (ii = Waypoint_lists.begin(); ii != Waypoint_lists.end(); ++ii) {
2822 		for (z=0; z<obj_count; z++){
2823 			if (names[z]){
2824 				if (!stricmp(names[z], ii->get_name())){
2825 					return internal_error("Waypoint path name is also used by an object (%s)", names[z]);
2826 				}
2827 			}
2828 		}
2829 
2830 		for (j = 0; (uint) j < ii->get_waypoints().size(); j++) {
2831 			sprintf(buf, "%s:%d", ii->get_name(), j + 1);
2832 			for (z=0; z<obj_count; z++){
2833 				if (names[z]){
2834 					if (!stricmp(names[z], buf)){
2835 						break;
2836 					}
2837 				}
2838 			}
2839 
2840 			if (z == obj_count){
2841 				return internal_error("Waypoint \"%s\" not linked to an object", buf);
2842 			}
2843 		}
2844 	}
2845 
2846 	if (Player_starts > MAX_PLAYERS){
2847 		return internal_error("Number of player starts exceeds max limit");
2848 	}
2849 
2850 	if (!multi && (Player_starts > 1)){
2851 		if (error("Multiple player starts exist, but this is a single player mission")){
2852 			return 1;
2853 		}
2854 	}
2855 
2856 	if (Num_reinforcements > MAX_REINFORCEMENTS){
2857 		return internal_error("Number of reinforcements exceeds max limit");
2858 	}
2859 
2860 	for (i=0; i<Num_reinforcements; i++) {
2861 		z = 0;
2862 		for (ship=0; ship<MAX_SHIPS; ship++){
2863 			if ((Ships[ship].objnum >= 0) && !stricmp(Ships[ship].ship_name, Reinforcements[i].name)) {
2864 				z = 1;
2865 				break;
2866 			}
2867 		}
2868 
2869 		for (wing=0; wing<MAX_WINGS; wing++){
2870 			if (Wings[wing].wave_count && !stricmp(Wings[wing].name, Reinforcements[i].name)) {
2871 				z = 1;
2872 				break;
2873 			}
2874 		}
2875 
2876 		if (!z){
2877 			return internal_error("Reinforcement name not found in ships or wings");
2878 		}
2879 	}
2880 
2881 /*	for (i=0; i<num_messages; i++) {
2882 		if (Messages[i].num_times < 0)
2883 			return internal_error("Number of times to play message is negative");
2884 
2885 		z = Messages[i].who_from;
2886 		if (z < -1 || z >= MAX_SHIPS)  // hacked!  -1 should be illegal..
2887 			return internal_error("Message originator index is out of range");
2888 
2889 		if (Ships[z].objnum == -1)
2890 			return internal_error("Message originator points to nonexistant ship");
2891 
2892 		if (fred_check_sexp(Messages[i].sexp, OPR_BOOL,
2893 			"Message formula from \"%s\"", Ships[Messages[i].who_from].ship_name))
2894 				return -1;
2895 	}*/
2896 
2897 	Assert((Player_start_shipnum >= 0) && (Player_start_shipnum < MAX_SHIPS) && (Ships[Player_start_shipnum].objnum >= 0));
2898 	i = global_error_check_player_wings(multi);
2899 	if (i){
2900 		return i;
2901 	}
2902 
2903 	for (i=0; i<Num_mission_events; i++){
2904 		if (fred_check_sexp(Mission_events[i].formula, OPR_NULL, "mission event \"%s\"", Mission_events[i].name)){
2905 			return -1;
2906 		}
2907 	}
2908 
2909 	for (i=0; i<Num_goals; i++){
2910 		if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission goal \"%s\"", Mission_goals[i].name)){
2911 			return -1;
2912 		}
2913 	}
2914 
2915 	for ( bs = 0; bs < Num_teams; bs++ ) {
2916 		for (s=0; s<Briefings[bs].num_stages; s++) {
2917 			sp = &Briefings[bs].stages[s];
2918 			t = sp->num_icons;
2919 			for (i=0; i<t-1; i++){
2920 				for (j=i+1; j<t; j++) {
2921 					if ((sp->icons[i].id > 0) && (sp->icons[i].id == sp->icons[j].id)){
2922 						if (error("Duplicate icon IDs %d in briefing stage %d", sp->icons[i].id, s + 1)){
2923 							return 1;
2924 						}
2925 					}
2926 				}
2927 			}
2928 		}
2929 	}
2930 
2931 	for ( j = 0; j < Num_teams; j++ ) {
2932 		for (i=0; i<Debriefings[j].num_stages; i++) {
2933 			if (fred_check_sexp(Debriefings[j].stages[i].formula, OPR_BOOL, "debriefing stage %d", i + 1)){
2934 				return -1;
2935 			}
2936 		}
2937 	}
2938 
2939 	// for all wings, be sure that the orders accepted for all ships are the same for all ships
2940 	// in the wing
2941 	starting_orders = -1;
2942 	for (i=0; i<MAX_WINGS; i++) {
2943 		int default_orders, starting_wing;
2944 
2945 		if ( !Wings[i].wave_count ){
2946 			continue;
2947 		}
2948 
2949 		// determine if this wing is a starting wing of the player
2950 		starting_wing = (ship_starting_wing_lookup(Wings[i].name) != -1);
2951 
2952 		// first, be sure this isn't a reinforcement wing.
2953 		if ( starting_wing && (Wings[i].flags & WF_REINFORCEMENT) ) {
2954 			if ( error("Starting Wing %s marked as reinforcement.  This wing\nshould either be renamed, or unmarked as reinforcement.", Wings[i].name) ){
2955 // Goober5000				return 1;
2956 			}
2957 		}
2958 
2959 		default_orders = 0;
2960 		for ( j = 0; j < Wings[i].wave_count; j++ ) {
2961 			int orders;
2962 
2963 			orders = Ships[Wings[i].ship_index[j]].orders_accepted;
2964 			if ( j == 0 ) {
2965 				default_orders = orders;
2966 			} else if ( default_orders != orders ) {
2967 				if (error("%s and %s will accept different orders. All ships in a wing must accept the same Player Orders.", Ships[Wings[i].ship_index[j]].ship_name, Ships[Wings[i].ship_index[0]].ship_name ) ){
2968 					return 1;
2969 				}
2970 			}
2971 		}
2972 
2973 /* Goober5000 - this is not necessary
2974 		// make sure that these ignored orders are the same for all starting wings of the player
2975 		if ( starting_wing ) {
2976 			if ( starting_orders == -1 ) {
2977 				starting_orders = default_orders;
2978 			} else {
2979 				if ( starting_orders != default_orders ) {
2980 					if ( error("Player starting wing %s has orders which don't match other starting wings\n", Wings[i].name) ){
2981 // Goober5000						return 1;
2982 					}
2983 				}
2984 			}
2985 		}
2986 */
2987 	}
2988 
2989 	//This should never ever be a problem -WMC
2990 	/*
2991 	if (Num_jump_nodes < 0){
2992 		return internal_error("Jump node count is illegal");
2993 	}*/
2994 
2995 	fred_check_message_personas();
2996 
2997 	return g_err;
2998 }
2999 
global_error_check_mixed_player_wing(int w)3000 int CFREDView::global_error_check_mixed_player_wing(int w)
3001 {
3002 	int i, s, species = -1, mixed = 0;
3003 
3004 	for (i=0; i<Wings[w].wave_count; i++) {
3005 		s = Wings[w].ship_index[i];
3006 		if (species < 0)
3007 			species = Ship_info[Ships[s].ship_info_index].species;
3008 		else if (Ship_info[Ships[s].ship_info_index].species != species)
3009 			mixed = 1;
3010 	}
3011 
3012 	if (mixed)
3013 		if (error("%s wing must all be of the same species", Wings[w].name))
3014 			return 1;
3015 
3016 	return 0;
3017 }
3018 
global_error_check_player_wings(int multi)3019 int CFREDView::global_error_check_player_wings(int multi)
3020 {
3021 	int i, z, err;
3022 	int starting_wing_count[MAX_STARTING_WINGS];
3023 	int tvt_wing_count[MAX_TVT_WINGS];
3024 
3025 	object *ptr;
3026 	CString starting_wing_list = "";
3027 	CString tvt_wing_list = "";
3028 
3029 	// check team wings in tvt
3030 	if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
3031 	{
3032 		for (i=0; i<MAX_TVT_WINGS; i++)
3033 		{
3034 			if (ship_tvt_wing_lookup(TVT_wing_names[i]) == -1)
3035 			{
3036 				if (error("%s wing is required for multiplayer team vs. team missions"))
3037 					return 1;
3038 			}
3039 		}
3040 	}
3041 
3042 //	// player's wing must have a true arrival
3043 //	free_sexp2(Wings[z].arrival_cue);
3044 //	Wings[z].arrival_cue = Locked_sexp_true;
3045 
3046 	// Check to be sure that any player wing doesn't have > 1 wave for multiplayer
3047 	if ( multi )
3048 	{
3049 		if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
3050 		{
3051 			for (i=0; i<MAX_TVT_WINGS; i++)
3052 			{
3053 				if (TVT_wings[i] >= 0 && Wings[TVT_wings[i]].num_waves > 1)
3054 				{
3055 					Wings[TVT_wings[i]].num_waves = 1;
3056 					if (error("%s wing must contain only 1 wave.\nThis change has been made for you.", TVT_wing_names[i]))
3057 						return 1;
3058 				}
3059 			}
3060 		}
3061 		else
3062 		{
3063 			for (i=0; i<MAX_STARTING_WINGS; i++)
3064 			{
3065 				if (Starting_wings[i] >= 0 && Wings[Starting_wings[i]].num_waves > 1)
3066 				{
3067 					Wings[Starting_wings[i]].num_waves = 1;
3068 					if (error("%s wing must contain only 1 wave.\nThis change has been made for you.", Starting_wing_names[i]))
3069 						return 1;
3070 				}
3071 			}
3072 		}
3073 	}
3074 
3075 	// check number of ships in player wing
3076 	if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
3077 	{
3078 		for (i=0; i<MAX_TVT_WINGS; i++)
3079 		{
3080 			if (TVT_wings[i] >= 0 && Wings[TVT_wings[i]].wave_count > 4)
3081 			{
3082 				if (error("%s wing has too many ships.  Should only have 4 max.", TVT_wing_names[i]))
3083 					return 1;
3084 			}
3085 		}
3086 	}
3087 	else
3088 	{
3089 		for (i=0; i<MAX_STARTING_WINGS; i++)
3090 		{
3091 			if (Starting_wings[i] >= 0 && Wings[Starting_wings[i]].wave_count > 4)
3092 			{
3093 				if (error("%s wing has too many ships.  Should only have 4 max.", Starting_wing_names[i]))
3094 					return 1;
3095 			}
3096 		}
3097 	}
3098 
3099 	// check arrival delay in tvt
3100 	if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
3101 	{
3102 		for (i=0; i<MAX_TVT_WINGS; i++)
3103 		{
3104 			if (TVT_wings[i] >= 0 && Wings[TVT_wings[i]].arrival_delay > 0)
3105 			{
3106 				if (error("%s wing shouldn't have a non-zero arrival delay", TVT_wing_names[i]))
3107 					return 1;
3108 			}
3109 		}
3110 	}
3111 
3112 	// check mixed-species in a wing for multi missions
3113 	if (multi)
3114 	{
3115 		if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
3116 		{
3117 			for (i=0; i<MAX_TVT_WINGS; i++)
3118 			{
3119 				if (TVT_wings[i] >= 0)
3120 				{
3121 					if (global_error_check_mixed_player_wing(TVT_wings[i]))
3122 						return 1;
3123 				}
3124 			}
3125 		}
3126 		else
3127 		{
3128 			for (i=0; i<MAX_STARTING_WINGS; i++)
3129 			{
3130 				if (Starting_wings[i] >= 0)
3131 				{
3132 					if (global_error_check_mixed_player_wing(Starting_wings[i]))
3133 						return 1;
3134 				}
3135 			}
3136 		}
3137 	}
3138 
3139 	for (i=0; i<MAX_STARTING_WINGS; i++)
3140 	{
3141 		starting_wing_count[i] = 0;
3142 
3143 		if (i < MAX_STARTING_WINGS - 1)
3144 		{
3145 			starting_wing_list += Starting_wing_names[i];
3146 			if (MAX_STARTING_WINGS > 2)
3147 				starting_wing_list += ",";
3148 			starting_wing_list += " ";
3149 		}
3150 		else
3151 		{
3152 			starting_wing_list += "or ";
3153 			starting_wing_list += Starting_wing_names[i];
3154 		}
3155 	}
3156 	for (i=0; i<MAX_TVT_WINGS; i++)
3157 	{
3158 		tvt_wing_count[i] = 0;
3159 
3160 		if (i < MAX_TVT_WINGS - 1)
3161 		{
3162 			tvt_wing_list += TVT_wing_names[i];
3163 			if (MAX_TVT_WINGS > 2)
3164 				tvt_wing_list += ",";
3165 			tvt_wing_list += " ";
3166 		}
3167 		else
3168 		{
3169 			tvt_wing_list += "or ";
3170 			tvt_wing_list += TVT_wing_names[i];
3171 		}
3172 	}
3173 
3174 	// check players in wings
3175 	ptr = GET_FIRST(&obj_used_list);
3176 	while (ptr != END_OF_LIST(&obj_used_list))
3177 	{
3178 		int ship_instance = ptr->instance;
3179 		err = 0;
3180 
3181 		// this ship is a player?
3182 		if (ptr->type == OBJ_START)
3183 		{
3184 			// check if this ship is in a wing
3185 			z = Ships[ship_instance].wingnum;
3186 			if (z < 0)
3187 			{
3188 				err = 1;
3189 			}
3190 			else
3191 			{
3192 				int in_starting_wing = 0;
3193 				int in_tvt_wing = 0;
3194 
3195 				// check which wing the player is in
3196 				for (i=0; i<MAX_STARTING_WINGS; i++)
3197 				{
3198 					if (Starting_wings[i] == z)
3199 					{
3200 						in_starting_wing = 1;
3201 						starting_wing_count[i]++;
3202 					}
3203 				}
3204 				for (i=0; i<MAX_TVT_WINGS; i++)
3205 				{
3206 					if (TVT_wings[i] == z)
3207 					{
3208 						in_tvt_wing = 1;
3209 						tvt_wing_count[i]++;
3210 					}
3211 				}
3212 
3213 				// make sure the player belongs to his proper wing
3214 				if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
3215 				{
3216 					if (!in_tvt_wing)
3217 					{
3218 						err = 1;
3219 					}
3220 				}
3221 				else
3222 				{
3223 					if (!in_starting_wing)
3224 					{
3225 						err = 1;
3226 					}
3227 				}
3228 			}
3229 
3230 			if (err)
3231 			{
3232 				if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
3233 				{
3234 					if (error("Player %s should be part of %s wing", Ships[ship_instance].ship_name, tvt_wing_list))
3235 						return 1;
3236 				}
3237 				else
3238 				{
3239 					if (error("Player %s should be part of %s wing", Ships[ship_instance].ship_name, starting_wing_list))
3240 						return 1;
3241 				}
3242 			}
3243 		}
3244 
3245 		ptr = GET_NEXT(ptr);
3246 	}
3247 
3248 	// check all wings in tvt have players
3249 	if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
3250 	{
3251 		for (i=0; i<MAX_TVT_WINGS; i++)
3252 		{
3253 			if (!tvt_wing_count[i])
3254 			{
3255 				if (error("%s wing doesn't contain any players (which it should)", TVT_wing_names[i]))
3256 					return 1;
3257 			}
3258 		}
3259 	}
3260 
3261 	return 0;
3262 }
3263 
error(const char * msg,...)3264 int CFREDView::error(const char *msg, ...)
3265 {
3266 	char buf[2048];
3267 	va_list args;
3268 
3269 	va_start(args, msg);
3270 	vsprintf(buf, msg, args);
3271 	va_end(args);
3272 
3273 	g_err = 1;
3274 	if (MessageBox(buf, "Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
3275 		return 0;
3276 
3277 	return 1;
3278 }
3279 
internal_error(const char * msg,...)3280 int CFREDView::internal_error(const char *msg, ...)
3281 {
3282 	char buf[2048];
3283 	va_list args;
3284 
3285 	va_start(args, msg);
3286 	vsprintf(buf, msg, args);
3287 	va_end(args);
3288 
3289 	g_err = 1;
3290 
3291 #ifndef NDEBUG
3292 	char buf2[2048];
3293 
3294 	sprintf(buf2, "%s\n\nThis is an internal error.  Please let Jason\n"
3295 		"know about this so he can fix it.  Click cancel to debug.", buf);
3296 
3297 	if (MessageBox(buf2, "Internal Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
3298 		Int3();  // drop to debugger so the problem can be analyzed.
3299 
3300 #else
3301 	MessageBox(buf, "Error", MB_OK | MB_ICONEXCLAMATION);
3302 #endif
3303 
3304 	return -1;
3305 }
3306 
fred_check_sexp(int sexp,int type,const char * msg,...)3307 int CFREDView::fred_check_sexp(int sexp, int type, const char *msg, ...)
3308 {
3309 	SCP_string buf, sexp_buf, error_buf;
3310 	int err = 0, z, faulty_node;
3311 	va_list args;
3312 
3313 	va_start(args, msg);
3314 	vsprintf(buf, msg, args);
3315 	va_end(args);
3316 
3317 	if (sexp == -1)
3318 		return 0;
3319 
3320 	z = check_sexp_syntax(sexp, type, 1, &faulty_node);
3321 	if (!z)
3322 		return 0;
3323 
3324 	convert_sexp_to_string(sexp_buf, sexp, SEXP_ERROR_CHECK_MODE);
3325 	truncate_message_lines(sexp_buf, 30);
3326 	sprintf(error_buf, "Error in %s: %s\n\nIn sexpression: %s\n\n(Error appears to be: %s)", buf.c_str(), sexp_error_message(z), sexp_buf.c_str(), Sexp_nodes[faulty_node].text);
3327 
3328 	if (z < 0 && z > -100)
3329 		err = 1;
3330 
3331 	if (err)
3332 		return internal_error(error_buf.c_str());
3333 
3334 	if (error(error_buf.c_str()))
3335 		return 1;
3336 
3337 	return 0;
3338 }
3339 
OnEditorsWaypoint()3340 void CFREDView::OnEditorsWaypoint()
3341 {
3342 	int adjust = 0;
3343 
3344 	Assert(Waypoint_editor_dialog.GetSafeHwnd());
3345 	if (!Show_sexp_help)
3346 		adjust = -SEXP_HELP_BOX_SIZE;
3347 
3348 	if (!theApp.init_window(&Waypoint_wnd_data, &Waypoint_editor_dialog))
3349 		return;
3350 
3351 	Waypoint_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
3352 		SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
3353 	Waypoint_editor_dialog.ShowWindow(SW_RESTORE);
3354 }
3355 
error_check_initial_orders(ai_goal * goals,int ship,int wing)3356 char *error_check_initial_orders(ai_goal *goals, int ship, int wing)
3357 {
3358 	char *source;
3359 	int i, j, num, flag, found, inst, team, team2;
3360 	object *ptr;
3361 
3362 	if (ship >= 0) {
3363 		source = Ships[ship].ship_name;
3364 		team = Ships[ship].team;
3365 		for (i=0; i<MAX_AI_GOALS; i++)
3366 			if (!ai_query_goal_valid(ship, goals[i].ai_mode)) {
3367 				if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode), source))
3368 					return "!";
3369 			}
3370 
3371 	} else {
3372 		Assert(wing >= 0);
3373 		Assert(Wings[wing].wave_count > 0);
3374 		source = Wings[wing].name;
3375 		team = Ships[Objects[wing_objects[wing][0]].instance].team;
3376 		for (j=0; j<Wings[wing].wave_count; j++)
3377 			for (i=0; i<MAX_AI_GOALS; i++)
3378 				if (!ai_query_goal_valid(Wings[wing].ship_index[j], goals[i].ai_mode)) {
3379 					if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode),
3380 						Ships[Wings[wing].ship_index[j]].ship_name))
3381 							return "!";
3382 				}
3383 	}
3384 
3385 	for (i=0; i<MAX_AI_GOALS; i++) {
3386 		switch (goals[i].ai_mode) {
3387 			case AI_GOAL_NONE:
3388 			case AI_GOAL_CHASE_ANY:
3389 			case AI_GOAL_UNDOCK:
3390 			case AI_GOAL_KEEP_SAFE_DISTANCE:
3391 			case AI_GOAL_PLAY_DEAD:
3392 			case AI_GOAL_WARP:
3393 				flag = 0;
3394 				break;
3395 
3396 			case AI_GOAL_WAYPOINTS:
3397 			case AI_GOAL_WAYPOINTS_ONCE:
3398 				flag = 1;
3399 				break;
3400 
3401 			case AI_GOAL_DOCK:
3402 				if (ship < 0)
3403 					return "Wings can't dock";
3404 				// fall through..
3405 
3406 			case AI_GOAL_DESTROY_SUBSYSTEM:
3407 			case AI_GOAL_CHASE:
3408 			case AI_GOAL_GUARD:
3409 			case AI_GOAL_DISARM_SHIP:
3410 			case AI_GOAL_DISABLE_SHIP:
3411 			case AI_GOAL_EVADE_SHIP:
3412 			case AI_GOAL_STAY_NEAR_SHIP:
3413 			case AI_GOAL_IGNORE:
3414 			case AI_GOAL_IGNORE_NEW:
3415 				flag = 2;
3416 				break;
3417 
3418 			case AI_GOAL_CHASE_WING:
3419 			case AI_GOAL_GUARD_WING:
3420 				flag = 3;
3421 				break;
3422 
3423 			case AI_GOAL_STAY_STILL:
3424 				flag = 4;
3425 				break;
3426 
3427 			default:
3428 				return "*Invalid goal type";
3429 		}
3430 
3431 		found = 0;
3432 		if (flag > 0) {
3433 			if (*goals[i].target_name == '<')
3434 				return "Invalid target";
3435 
3436 			if (!stricmp(goals[i].target_name, source))
3437 				if (ship >= 0)
3438 					return "Target of ship's goal is itself";
3439 				else
3440 					return "Target of wing's goal is itself";
3441 		}
3442 
3443 		inst = team2 = -1;
3444 		if (flag == 1) {  // target waypoint required
3445 			if (find_matching_waypoint_list(goals[i].target_name) == NULL)
3446 				return "*Invalid target waypoint path name";
3447 
3448 		} else if (flag == 2) {  // target ship required
3449 			ptr = GET_FIRST(&obj_used_list);
3450 			while (ptr != END_OF_LIST(&obj_used_list)) {
3451 				if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3452 					inst = ptr->instance;
3453 					if (!stricmp(goals[i].target_name, Ships[inst].ship_name)) {
3454 						found = 1;
3455 						break;
3456 					}
3457 				}
3458 
3459 				ptr = GET_NEXT(ptr);
3460 			}
3461 
3462 			if (!found)
3463 				return "*Invalid target ship name";
3464 
3465 			if (wing >= 0) {  // check if target ship is in wing
3466 				if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3467 					return "Target ship of wing's goal is within said wing";
3468 			}
3469 
3470 			team2 = Ships[inst].team;
3471 
3472 		} else if (flag == 3) {  // target wing required
3473 			for (j=0; j<MAX_WINGS; j++)
3474 				if (Wings[j].wave_count && !stricmp(Wings[j].name, goals[i].target_name))
3475 					break;
3476 
3477 			if (j >= MAX_WINGS)
3478 				return "*Invalid target wing name";
3479 
3480 			if (ship >= 0) {  // check if ship is in target wing
3481 				if (Ships[ship].wingnum == j)
3482 					return "Target wing of ship's goal is same wing said ship is part of";
3483 			}
3484 
3485 			team2 = Ships[Objects[wing_objects[j][0]].instance].team;
3486 
3487 		} else if (flag == 4) {
3488 			ptr = GET_FIRST(&obj_used_list);
3489 			while (ptr != END_OF_LIST(&obj_used_list)) {
3490 				if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3491 					inst = ptr->instance;
3492 					if (!stricmp(goals[i].target_name, Ships[inst].ship_name)) {
3493 						found = 2;
3494 						break;
3495 					}
3496 
3497 				} else if (ptr->type == OBJ_WAYPOINT) {
3498 					if (!stricmp(goals[i].target_name, object_name(OBJ_INDEX(ptr)))) {
3499 						found = 1;
3500 						break;
3501 					}
3502 				}
3503 
3504 				ptr = GET_NEXT(ptr);
3505 			}
3506 
3507 			if (!found)
3508 				return "*Invalid target ship or waypoint name";
3509 
3510 			if (found == 2) {
3511 				if (wing >= 0) {  // check if target ship is in wing
3512 					if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3513 						return "Target ship of wing's goal is within said wing";
3514 				}
3515 
3516 				team2 = Ships[inst].team;
3517 			}
3518 		}
3519 
3520 		switch (goals[i].ai_mode) {
3521 			case AI_GOAL_DESTROY_SUBSYSTEM:
3522 				Assert(flag == 2 && inst >= 0);
3523 				if (ship_get_subsys_index(&Ships[inst], goals[i].docker.name, 1) < 0)
3524 					return "Unknown subsystem type";
3525 
3526 				break;
3527 
3528 			case AI_GOAL_DOCK: {
3529 				int dock1 = -1, dock2 = -1, model1, model2;
3530 
3531 				Assert(flag == 2 && inst >= 0);
3532 				if (!ship_docking_valid(ship, inst))
3533 					return "Docking illegal between given ship types";
3534 
3535 				model1 = Ship_info[Ships[ship].ship_info_index].model_num;
3536 				num = get_docking_list(model1);
3537 				for (j=0; j<num; j++) {
3538 					Assert(Docking_bay_list[j]);
3539 					if (!stricmp(goals[i].docker.name, Docking_bay_list[j])) {
3540 						dock1 = j;
3541 						break;
3542 					}
3543 				}
3544 
3545 				model2 = Ship_info[Ships[inst].ship_info_index].model_num;
3546 				num = get_docking_list(model2);
3547 				for (j=0; j<num; j++) {
3548 					Assert(Docking_bay_list[j]);
3549 					if (!stricmp(goals[i].dockee.name, Docking_bay_list[j])) {
3550 						dock2 = j;
3551 						break;
3552 					}
3553 				}
3554 
3555 				if (dock1 < 0)
3556 					return "Invalid docker point";
3557 
3558 				if (dock2 < 0)
3559 					return "Invalid dockee point";
3560 
3561 				if ((dock1 >= 0) && (dock2 >= 0)) {
3562 					if ( !(model_get_dock_index_type(model1, dock1) & model_get_dock_index_type(model2, dock2)) )
3563 						return "Dock points are incompatible";
3564 				}
3565 
3566 				break;
3567 			}
3568 		}
3569 
3570 		switch (goals[i].ai_mode) {
3571 			case AI_GOAL_GUARD:
3572 			case AI_GOAL_GUARD_WING:
3573 				if (team != team2) {	//	MK, added support for TEAM_NEUTRAL.  Won't this work?
3574 					if (ship >= 0)
3575 						return "Ship assigned to guard a different team";
3576 					else
3577 						return "Wing assigned to guard a different team";
3578 				}
3579 
3580 				break;
3581 
3582 			case AI_GOAL_CHASE:
3583 			case AI_GOAL_CHASE_WING:
3584 			case AI_GOAL_DESTROY_SUBSYSTEM:
3585 			case AI_GOAL_DISARM_SHIP:
3586 			case AI_GOAL_DISABLE_SHIP:
3587 				if (team == team2) {
3588 					if (ship >= 0)
3589 						return "Ship assigned to attack same team";
3590 					else
3591 						return "Wings assigned to attack same team";
3592 				}
3593 
3594 				break;
3595 		}
3596 	}
3597 
3598 	return NULL;
3599 }
3600 
3601 // function (which is called externally from message editor and event editor) so skip through
3602 // the sexpression nodes to look for send-message commands to try to associate message personas
3603 // to ships
fred_check_message_personas()3604 void fred_check_message_personas()
3605 {
3606 /*
3607 	int i, op, j, ship_index;
3608 	char *mname, *who_from;
3609 	object *objp;
3610 
3611 	// this function is responsible for assigning personas to ships as well as error checking them.
3612 	// clear out the persona index on all ship objects
3613 	for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3614 		if ( objp->type == OBJ_SHIP ) {
3615 			Ships[objp->instance].persona_index = -1;
3616 		}
3617 	}
3618 
3619 
3620 	for (i = 0; i < Num_sexp_nodes; i++ ) {
3621 		if ( Sexp_nodes[i].type == SEXP_NOT_USED )
3622 			continue;
3623 
3624 		// look for only operator nodes
3625 		if ( Sexp_nodes[i].subtype != SEXP_ATOM_OPERATOR )
3626 			continue;
3627 
3628 		// now look for the send-message opeator
3629 		op = get_operator_const( Sexp_nodes[i].text );
3630 		if ( op != OP_SEND_MESSAGE )
3631 			continue;
3632 
3633 		// have the message.  parse through the message to determine who is sending the message.
3634 		who_from = CTEXT(CDR(i));
3635 
3636 		// we can ignore messages from any wingman, and allied, or from God.
3637 		if ( !stricmp(who_from, "<Any wingman>") || !stricmp(who_from, "<Any allied>") || (who_from[0] == '#') )
3638 			continue;
3639 
3640 		mname = CTEXT(CDR(CDR(CDR(i))));
3641 
3642 		// check to see if who_from is a wing.  Don't do processing if so.
3643 		if ( wing_name_lookup(who_from, 1) != -1 )
3644 			continue;
3645 
3646 		ship_index = ship_name_lookup( who_from );
3647 		if ( ship_index == -1 ) {
3648 			Int3();			// get allender.  something funny is up with shipnames in send-message
3649 			continue;
3650 		}
3651 
3652 		for ( j = Num_builtin_messages; j < Num_messages; j++ ) {
3653 			if ( !stricmp(mname, Messages[j].name) ) {
3654 
3655 				// check to see if there is a persona for this message -- if not, bail
3656 				if ( Messages[j].persona_index == -1 )
3657 					break;
3658 
3659 				// if a ship isn't assigned a persona, and this message says that he is, assign it, and move on
3660 				if ( Ships[ship_index].persona_index == -1 ) {
3661 					Ships[ship_index].persona_index = Messages[j].persona_index;
3662 					continue;
3663 				}
3664 
3665 				// we must be sure of the following conditions:
3666 				// 1) a ship isn't assigned > 1 persona
3667 
3668 				if ( Ships[ship_index].persona_index != Messages[j].persona_index )
3669 					Fred_view_wnd->error("Ship %s has at least two personas attached to it:\n%s and %s", Ships[ship_index].ship_name, Personas[Ships[ship_index].persona_index].name, Personas[Messages[j].persona_index].name );
3670 			}
3671 		}
3672 	}
3673 
3674 	// check that two or more ships are not using the same persona
3675 	for (i = 0; i < Num_personas; i++ ) {
3676 		int persona_count;
3677 		object *objp;
3678 
3679 		// move through object list looking for number of shis using this persona
3680 		persona_count = 0;
3681 		for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3682 			if ( objp->type != OBJ_SHIP )
3683 				continue;
3684 			if (Ships[objp->instance].persona_index == i )
3685 				persona_count++;
3686 		}
3687 
3688 		if ( persona_count > 1 )
3689 			Fred_view_wnd->error("Persona %s used by more than 1 ship", Personas[Messages[j].persona_index].name );
3690 	}
3691 */
3692 
3693 }
3694 
OnViewOutlines()3695 void CFREDView::OnViewOutlines()
3696 {
3697 	Show_outlines = !Show_outlines;
3698 	theApp.write_ini_file();
3699 	Update_window = 1;
3700 }
3701 
OnUpdateViewOutlines(CCmdUI * pCmdUI)3702 void CFREDView::OnUpdateViewOutlines(CCmdUI* pCmdUI)
3703 {
3704 	pCmdUI->SetCheck(Show_outlines);
3705 }
3706 
OnUpdateNewShipType(CCmdUI * pCmdUI)3707 void CFREDView::OnUpdateNewShipType(CCmdUI* pCmdUI)
3708 {
3709 	int z;
3710 	CWnd *bar;
3711 
3712 	z = m_new_ship_type_combo_box.GetCurSelNEW();
3713 	if (z == CB_ERR)
3714 		m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
3715 	else
3716 		cur_model_index = z;
3717 
3718 	bar = GetDlgItem(pCmdUI->m_nID);
3719 	if (!bar) {
3720 		pCmdUI -> ContinueRouting();
3721 		return; // not for us
3722 	}
3723 
3724 	pCmdUI -> SetCheck((bar->GetStyle() & WS_VISIBLE) != 0);
3725 }
3726 
OnShowStarfield()3727 void CFREDView::OnShowStarfield()
3728 {
3729 	Show_stars = !Show_stars;
3730 	theApp.write_ini_file();
3731 	Update_window = 1;
3732 }
3733 
OnUpdateShowStarfield(CCmdUI * pCmdUI)3734 void CFREDView::OnUpdateShowStarfield(CCmdUI* pCmdUI)
3735 {
3736 	pCmdUI->SetCheck(Show_stars);
3737 }
3738 
OnAsteroidEditor()3739 void CFREDView::OnAsteroidEditor()
3740 {
3741 	asteroid_editor dlg;
3742 
3743 	dlg.DoModal();
3744 }
3745 
OnRunFreeSpace()3746 void CFREDView::OnRunFreeSpace()
3747 {
3748 	BOOL r;
3749 	STARTUPINFO si;
3750 	PROCESS_INFORMATION pi;
3751 	char *lpMsgBuf;
3752 
3753 	if (!FREDDoc_ptr->SaveModified())
3754 		return;
3755 
3756 	si.cb = sizeof(si);
3757 	si.lpReserved = NULL;
3758 	si.lpDesktop = NULL;
3759 	si.lpTitle = NULL;
3760 	si.dwFlags = 0;
3761 	si.cbReserved2 = 0;
3762 	si.lpReserved2 = NULL;
3763 
3764 	// get the filename of the app and replace FRED2_Open with FS2_Open
3765 	std::string processed_name(AfxGetApp()->m_pszExeName);
3766 	std::string::size_type fred_index = processed_name.find("fred2_open", 0);
3767 	// capitalisation!
3768 	if (fred_index == std::string::npos) {
3769 		fred_index = processed_name.find("Fred2_Open", 0);
3770 	}
3771 
3772 	if (fred_index != std::string::npos) {
3773 		// delete the fred2_open and add FS2_Open in its place
3774 		processed_name.erase(fred_index, 10);
3775 		processed_name.insert(fred_index, "FS2_Open");
3776 		processed_name.append(".exe");
3777 
3778 		//try to start FS2_open
3779 		r = CreateProcess(processed_name.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, "./", &si, &pi);
3780 		if (r) {
3781 			return;
3782 		}
3783 	}
3784 
3785 	r = CreateProcess("start_fs2.bat", NULL, NULL, NULL, FALSE, 0, NULL, "./", &si, &pi);
3786 
3787 	if (!r) {
3788 		r = CreateProcess("fs2_open.exe", NULL, NULL, NULL, FALSE, 0, NULL, "./", &si, &pi);
3789 	}
3790 
3791 	if (!r) {
3792 		r = CreateProcess("fs2_open_r.exe", NULL, NULL, NULL, FALSE, 0, NULL, "./", &si, &pi);
3793 	}
3794 
3795 	if (!r) {
3796 		FormatMessage(
3797 			 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
3798 			 NULL,
3799 			 GetLastError(),
3800 			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
3801 			 (LPTSTR) &lpMsgBuf,
3802 			 0,
3803 			 NULL
3804 		);
3805 
3806 		// Display the string.
3807 		MessageBox(lpMsgBuf);
3808 
3809 		// Free the buffer.
3810 		LocalFree( lpMsgBuf );
3811 	}
3812 }
3813 
OnEditorCampaign()3814 void CFREDView::OnEditorCampaign()
3815 {
3816 	if (!FREDDoc_ptr->SaveModified())
3817 		return;
3818 
3819 	Assert(!Campaign_wnd);
3820 	Campaign_wnd = new campaign_tree_wnd;
3821 	if (Campaign_wnd->Create(NULL, "Campaign Editor", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
3822 		CFrameWnd::rectDefault, NULL, "IDR_MENU_CAMPAIGN")) {
3823 		Campaign_wnd->ShowWindow(SW_SHOW);
3824 		Campaign_wnd->UpdateWindow();
3825 	}
3826 }
3827 
OnShowShips()3828 void CFREDView::OnShowShips()
3829 {
3830 	Show_ships = !Show_ships;
3831 	correct_marking();
3832 	Update_window = 1;
3833 }
3834 
OnUpdateShowShips(CCmdUI * pCmdUI)3835 void CFREDView::OnUpdateShowShips(CCmdUI* pCmdUI)
3836 {
3837 	pCmdUI->SetCheck(Show_ships);
3838 }
3839 
OnShowStarts()3840 void CFREDView::OnShowStarts()
3841 {
3842 	Show_starts = !Show_starts;
3843 	correct_marking();
3844 	Update_window = 1;
3845 }
3846 
OnUpdateShowStarts(CCmdUI * pCmdUI)3847 void CFREDView::OnUpdateShowStarts(CCmdUI* pCmdUI)
3848 {
3849 	pCmdUI->SetCheck(Show_starts);
3850 }
3851 
OnShowIFF(int iff)3852 void CFREDView::OnShowIFF(int iff)
3853 {
3854 	Show_iff[iff] = !Show_iff[iff];
3855 	correct_marking();
3856 	Update_window = 1;
3857 }
3858 
OnUpdateShowIFF(int iff,CCmdUI * pCmdUI)3859 void CFREDView::OnUpdateShowIFF(int iff, CCmdUI* pCmdUI)
3860 {
3861 	pCmdUI->SetCheck(Show_iff[iff]);
3862 }
3863 
OnToggleViewpoint()3864 void CFREDView::OnToggleViewpoint()
3865 {
3866 	if (viewpoint || !query_valid_object())
3867 		viewpoint = 0;
3868 
3869 	else {
3870 		viewpoint = 1;
3871 		view_obj = cur_object_index;
3872 	}
3873 
3874 	Update_window = 1;
3875 }
3876 
OnRevert()3877 void CFREDView::OnRevert()
3878 {
3879 	if (!FREDDoc_ptr->SaveModified())
3880 		return;
3881 
3882 	FREDDoc_ptr->DeleteContents();
3883 	FREDDoc_ptr->OnOpenDocument(NULL);
3884 }
3885 
OnUpdateRevert(CCmdUI * pCmdUI)3886 void CFREDView::OnUpdateRevert(CCmdUI* pCmdUI)
3887 {
3888 	pCmdUI->Enable(*Mission_filename);
3889 }
3890 
OnSetCursor(CWnd * pWnd,UINT nHitTest,UINT message)3891 BOOL CFREDView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
3892 {
3893 	if ((Cursor_over >= 0) || Selection_lock) {
3894 		if (Editing_mode == 1) {
3895 			SetCursor(h_cursor_move);
3896 			return TRUE;
3897 
3898 		} else if (Editing_mode == 2) {
3899 			SetCursor(h_cursor_rotate);
3900 			return TRUE;
3901 		}
3902 	}
3903 
3904 	return CView::OnSetCursor(pWnd, nHitTest, message);
3905 }
3906 
OnHideObjects()3907 void CFREDView::OnHideObjects()
3908 {
3909 	object *ptr;
3910 
3911 	ptr = GET_FIRST(&obj_used_list);
3912 	while (ptr != END_OF_LIST(&obj_used_list)) {
3913 		if (ptr->flags & OF_MARKED) {
3914 			ptr->flags |= OF_HIDDEN;
3915 			unmark_object(OBJ_INDEX(ptr));
3916 		}
3917 
3918 		ptr = GET_NEXT(ptr);
3919 	}
3920 }
3921 
OnShowHiddenObjects()3922 void CFREDView::OnShowHiddenObjects()
3923 {
3924 	object *ptr;
3925 
3926 	ptr = GET_FIRST(&obj_used_list);
3927 	while (ptr != END_OF_LIST(&obj_used_list)) {
3928 		ptr->flags &= ~OF_HIDDEN;
3929 		ptr = GET_NEXT(ptr);
3930 	}
3931 
3932 	Update_window = 1;
3933 }
3934 
OnEditUndo()3935 void CFREDView::OnEditUndo()
3936 {
3937 	vec3d viewer_pos;
3938 	matrix viewer_orient;
3939 
3940 	if (Undo_available) {
3941 		viewer_pos = view_pos;
3942 		viewer_orient = view_orient;
3943 		FREDDoc_ptr->autoload();
3944 		view_pos = viewer_pos;
3945 		view_orient = viewer_orient;
3946 	}
3947 }
3948 
OnUpdateEditUndo(CCmdUI * pCmdUI)3949 void CFREDView::OnUpdateEditUndo(CCmdUI* pCmdUI)
3950 {
3951 	pCmdUI->Enable(Undo_available);
3952 }
3953 
OnEditorsBriefing()3954 void CFREDView::OnEditorsBriefing()
3955 {
3956 	if (!Briefing_dialog) {
3957 		Briefing_dialog = new briefing_editor_dlg;
3958 		Briefing_dialog->create();
3959 	}
3960 
3961 	Briefing_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
3962 		SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
3963 	Briefing_dialog->ShowWindow(SW_RESTORE);
3964 }
3965 
OnEditorsDebriefing()3966 void CFREDView::OnEditorsDebriefing()
3967 {
3968 	debriefing_editor_dlg dlg;
3969 
3970 	dlg.DoModal();
3971 }
3972 
OnSaveCamera()3973 void CFREDView::OnSaveCamera()
3974 {
3975 	saved_cam_pos = view_pos;
3976 	saved_cam_orient = view_orient;
3977 }
3978 
OnRestoreCamera()3979 void CFREDView::OnRestoreCamera()
3980 {
3981 	view_pos = saved_cam_pos;
3982 	view_orient = saved_cam_orient;
3983 	Update_window = 1;
3984 }
3985 
OnUpdateRestoreCamera(CCmdUI * pCmdUI)3986 void CFREDView::OnUpdateRestoreCamera(CCmdUI* pCmdUI)
3987 {
3988 	pCmdUI->Enable(!IS_VEC_NULL(&saved_cam_orient.vec.fvec));
3989 }
3990 
OnShowSexpHelp()3991 void CFREDView::OnShowSexpHelp()
3992 {
3993 	CRect rect;
3994 
3995 	Show_sexp_help = !Show_sexp_help;
3996 	Ship_editor_dialog.show_hide_sexp_help();
3997 	Wing_editor_dialog.show_hide_sexp_help();
3998 
3999 	if (Event_editor_dlg) {
4000 		Event_editor_dlg->GetWindowRect(rect);
4001 		if (Show_sexp_help)
4002 			rect.bottom += SEXP_HELP_BOX_SIZE;
4003 		else
4004 			rect.bottom -= SEXP_HELP_BOX_SIZE;
4005 
4006 		Event_editor_dlg->MoveWindow(rect);
4007 	}
4008 }
4009 
OnUpdateShowSexpHelp(CCmdUI * pCmdUI)4010 void CFREDView::OnUpdateShowSexpHelp(CCmdUI* pCmdUI)
4011 {
4012 	pCmdUI->SetCheck(Show_sexp_help);
4013 }
4014 
OnLookatObj()4015 void CFREDView::OnLookatObj()
4016 {
4017 	Lookat_mode = !Lookat_mode;
4018 	if (Lookat_mode && query_valid_object()) {
4019 		vec3d v, loc;
4020 		matrix m;
4021 
4022 		loc = Objects[cur_object_index].pos;
4023 		vm_vec_sub(&v, &loc, &view_pos);
4024 
4025 		if (v.xyz.x || v.xyz.y || v.xyz.z) {
4026 			vm_vector_2_matrix(&m, &v, NULL, NULL);
4027 			view_orient = m;
4028 		}
4029 	}
4030 }
4031 
OnUpdateLookatObj(CCmdUI * pCmdUI)4032 void CFREDView::OnUpdateLookatObj(CCmdUI* pCmdUI)
4033 {
4034 	pCmdUI->SetCheck(Lookat_mode);
4035 }
4036 
OnGroup(UINT nID)4037 void CFREDView::OnGroup(UINT nID)
4038 {
4039 	int n = 1 << (nID - ID_GROUP1);
4040 	object *objp;
4041 
4042 	unmark_all();
4043 	objp = GET_FIRST(&obj_used_list);
4044 	while (objp != END_OF_LIST(&obj_used_list))	{
4045 		if (objp->type == OBJ_SHIP) {
4046 			if (Ships[objp->instance].group & n)
4047 				mark_object(OBJ_INDEX(objp));
4048 		}
4049 
4050 		objp = GET_NEXT(objp);
4051 	}
4052 
4053 	Update_window = 1;
4054 }
4055 
OnSetGroup(UINT nID)4056 void CFREDView::OnSetGroup(UINT nID)
4057 {
4058 	int i, err = 0, n = 1 << (nID - ID_SET_GROUP1);
4059 	object *objp;
4060 
4061 	for (i=0; i<MAX_SHIPS; i++)
4062 		Ships[i].group &= ~n;
4063 
4064 	objp = GET_FIRST(&obj_used_list);
4065 	while (objp != END_OF_LIST(&obj_used_list)) {
4066 		if (objp->flags & OF_MARKED) {
4067 			if (objp->type == OBJ_SHIP) {
4068 				Ships[objp->instance].group |= n;
4069 
4070 			} else
4071 				err = 1;
4072 		}
4073 
4074 		objp = GET_NEXT(objp);
4075 	}
4076 
4077 	if (err)
4078 		Fred_main_wnd->MessageBox("Only ships can be in groups, and not players or waypoints, etc.\n"
4079 			"These illegal objects you marked were not placed in the group");
4080 
4081 	Update_window = 1;
4082 }
4083 
OnInitialUpdate()4084 void CFREDView::OnInitialUpdate()
4085 {
4086 	char *ptr, text[512];
4087 
4088 	CView::OnInitialUpdate();
4089 
4090 	// check the time/checksum strings.
4091 	expire_game = 0;
4092 	ptr = &stamp[0];
4093 	if ( memcmp(ptr, DEFAULT_CHECKSUM_STRING, strlen(DEFAULT_CHECKSUM_STRING)) ) {
4094 		int stamped_checksum, checksum;
4095 
4096 		// the checksum is not the default checksum.  Calculate the checksum of the string
4097 		// and compare it.
4098 		memcpy(&stamped_checksum, ptr, sizeof(stamped_checksum) );
4099 		ptr = &stamp[0];
4100 		ptr += 8;			// get us to the actual string to calculate the checksum
4101 		CALCULATE_STAMP_CHECKSUM();
4102 
4103 		if ( checksum != stamped_checksum ){
4104 			expire_game = EXPIRE_BAD_CHECKSUM;
4105 		}
4106 
4107 		// now check the time
4108 		ptr = &stamp[0];
4109 		ptr += 4;
4110 		if ( memcmp( ptr, DEFAULT_TIME_STRING, strlen(DEFAULT_TIME_STRING)) ) {
4111 			int expire_time, current_time;
4112 
4113 			// not the default time -- check against the current time
4114 			memcpy( &expire_time, ptr, sizeof(expire_time) );
4115 			time( (time_t*)&current_time );
4116 			if ( current_time > expire_time )
4117 				expire_game = EXPIRE_BAD_TIME;
4118 		}
4119 
4120 		// since the default checksum has changed -- put up a message which shows who the program
4121 		// is stamped for
4122 		ptr = &stamp[0];
4123 		ptr += 8;
4124 		sprintf(text, "This version of Fred has been compiled for %s", ptr);
4125 		MessageBox(text, NULL, MB_OK);
4126 
4127 		if ( expire_game )
4128 			SetTimer(1, FRED_EXPIRE_TIME, expire_game_proc);
4129 	}
4130 }
4131 
OnEditorsAdjustGrid()4132 void CFREDView::OnEditorsAdjustGrid()
4133 {
4134 	adjust_grid_dlg dlg;
4135 
4136 	dlg.DoModal();
4137 	Update_window = 1;
4138 }
4139 
OnEditorsShieldSys()4140 void CFREDView::OnEditorsShieldSys()
4141 {
4142 	shield_sys_dlg dlg;
4143 
4144 	dlg.DoModal();
4145 }
4146 
OnLevelObj()4147 void CFREDView::OnLevelObj()
4148 {
4149 	level_controlled();
4150 	Update_window = 1;
4151 }
4152 
OnAlignObj()4153 void CFREDView::OnAlignObj()
4154 {
4155 	verticalize_controlled();
4156 	Update_window = 1;
4157 }
4158 
OnControlObj()4159 void CFREDView::OnControlObj()
4160 {
4161 	Control_mode = (Control_mode + 1) % 2;
4162 }
4163 
OnNextObj()4164 void CFREDView::OnNextObj()
4165 {
4166 	object *ptr;
4167 
4168 	if (Bg_bitmap_dialog) {
4169 		if (Cur_bitmap == -1)
4170 		{
4171 			if (stars_get_num_bitmaps())
4172 			{
4173 				Cur_bitmap = 0;
4174 				Bg_bitmap_dialog -> update_data();
4175 			}
4176 
4177 			return;
4178 		}
4179 
4180 		Cur_bitmap++;
4181 		if (Cur_bitmap >= stars_get_num_bitmaps())
4182 			Cur_bitmap = 0;
4183 
4184 		Bg_bitmap_dialog -> update_data();
4185 		return;
4186 	}
4187 
4188 	if (EMPTY(&obj_used_list))
4189 		return;
4190 
4191 	if (query_valid_object())	{
4192 		ptr = Objects[cur_object_index].next;
4193 		if (ptr == END_OF_LIST(&obj_used_list))
4194 			ptr = GET_NEXT(ptr);
4195 
4196 	} else
4197 		ptr = GET_FIRST(&obj_used_list);
4198 
4199 	if (Marked > 1) {  // cycle through marked list
4200 		while (!(ptr->flags & OF_MARKED))
4201 		{
4202 			ptr = GET_NEXT(ptr);
4203 			if (ptr == END_OF_LIST(&obj_used_list))
4204 				ptr = GET_NEXT(ptr);
4205 		}
4206 
4207 		set_cur_object_index(OBJ_INDEX(ptr));
4208 
4209 	} else {
4210 		if (Marked)
4211 			unmark_object(cur_object_index);
4212 
4213 		mark_object(OBJ_INDEX(ptr));
4214 	}
4215 }
4216 
OnPrevObj()4217 void CFREDView::OnPrevObj()
4218 {
4219 	int arr[MAX_OBJECTS], i = 0, n = 0;
4220 	object *ptr;
4221 
4222 	if (Bg_bitmap_dialog) {
4223 		if (Cur_bitmap == -1)
4224 		{
4225 			if (stars_get_num_bitmaps())
4226 			{
4227 				Cur_bitmap = stars_get_num_bitmaps() - 1;
4228 				Bg_bitmap_dialog -> update_data();
4229 			}
4230 
4231 			return;
4232 		}
4233 
4234 		Cur_bitmap--;
4235 		if (Cur_bitmap < 0)
4236 			Cur_bitmap = stars_get_num_bitmaps() - 1;
4237 
4238 		Bg_bitmap_dialog -> update_data();
4239 		return;
4240 	}
4241 
4242 	if (EMPTY(&obj_used_list))
4243 		return;
4244 
4245 	ptr = GET_FIRST(&obj_used_list);
4246 	while (ptr != END_OF_LIST(&obj_used_list)) {
4247 		if (cur_object_index == OBJ_INDEX(ptr))
4248 			i = n;
4249 
4250 		arr[n++] = OBJ_INDEX(ptr);
4251 		ptr = GET_NEXT(ptr);
4252 	}
4253 
4254 	Assert(n);
4255 	if (query_valid_object()) {
4256 		i--;
4257 		if (i < 0)
4258 			i = n - 1;
4259 
4260 	} else
4261 		i = n - 1;
4262 
4263 	if (Marked > 1) {  // cycle through marked list
4264 		while (!(Objects[i].flags & OF_MARKED))
4265 		{
4266 			i--;
4267 			if (i < 0)
4268 				i = n - 1;
4269 		}
4270 
4271 		set_cur_object_index(i);
4272 
4273 	} else {
4274 		if (Marked)
4275 			unmark_object(cur_object_index);
4276 
4277 		mark_object(i);
4278 	}
4279 }
4280 
OnEditDelete()4281 void CFREDView::OnEditDelete()
4282 {
4283 	if (!button_down && Marked) {
4284 		delete_marked();
4285 		FREDDoc_ptr->autosave("object delete");
4286 	}
4287 
4288 	Update_window = 2;  // For some strange reason, need to redraw twice for it to take.
4289 }
4290 
OnEditDeleteWing()4291 void CFREDView::OnEditDeleteWing()
4292 {
4293 	if (!button_down && (cur_wing >= 0)) {
4294 		delete_wing();
4295 		FREDDoc_ptr->autosave("wing delete");
4296 		cur_wing = -1;
4297 		if (!Marked)
4298 			Ship_editor_dialog.initialize_data(1);
4299 
4300 		Wing_editor_dialog.initialize_data(1);
4301 	}
4302 
4303 	Update_window = 2;  // For some strange reason, need to redraw twice for it to take.
4304 }
4305 
OnMarkWing()4306 void CFREDView::OnMarkWing()
4307 {
4308 	int i, wing = cur_wing;
4309 
4310 	if (wing != -1)
4311 	{
4312 		unmark_all();
4313 		for (i=0; i<Wings[wing].wave_count; i++)
4314 			mark_object(wing_objects[wing][i]);
4315 
4316 		Assert(Wings[wing].special_ship >= 0 && Wings[wing].special_ship < Wings[wing].wave_count);
4317 		set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]);
4318 	}
4319 }
4320 
OnUpdateControlObj(CCmdUI * pCmdUI)4321 void CFREDView::OnUpdateControlObj(CCmdUI* pCmdUI)
4322 {
4323 	pCmdUI->SetCheck(Control_mode != 0);
4324 }
4325 
OnAaGridlines()4326 void CFREDView::OnAaGridlines()
4327 {
4328 	Aa_gridlines = !Aa_gridlines;
4329 }
4330 
OnUpdateAaGridlines(CCmdUI * pCmdUI)4331 void CFREDView::OnUpdateAaGridlines(CCmdUI* pCmdUI)
4332 {
4333 	pCmdUI->SetCheck(Aa_gridlines);
4334 	Update_window = 1;
4335 }
4336 
OnCmdBrief()4337 void CFREDView::OnCmdBrief()
4338 {
4339 	cmd_brief_dlg dlg;
4340 
4341 	dlg.DoModal();
4342 	Update_window = 1;
4343 }
4344 
OnDisableUndo()4345 void CFREDView::OnDisableUndo()
4346 {
4347 	Autosave_disabled = !Autosave_disabled;
4348 }
4349 
OnUpdateDisableUndo(CCmdUI * pCmdUI)4350 void CFREDView::OnUpdateDisableUndo(CCmdUI* pCmdUI)
4351 {
4352 	pCmdUI->SetCheck(Autosave_disabled);
4353 }
4354 
OnUpdateCmdBrief(CCmdUI * pCmdUI)4355 void CFREDView::OnUpdateCmdBrief(CCmdUI* pCmdUI)
4356 {
4357 	pCmdUI->Enable(!(The_mission.game_type & MISSION_TYPE_MULTI));
4358 }
4359 
get_visible_sub_system_count(ship * shipp)4360 int get_visible_sub_system_count(ship *shipp)
4361 {
4362 	int count = 0;
4363 	ship_subsys *cur_subsys;
4364 
4365 	for (cur_subsys = GET_FIRST(&shipp->subsys_list); cur_subsys != END_OF_LIST(&shipp->subsys_list); cur_subsys = GET_NEXT(cur_subsys)) {
4366 		if (cur_subsys->system_info->subobj_num != -1) {
4367 			count++;
4368 		}
4369 	}
4370 
4371 	return count;
4372 }
4373 
get_next_visible_subsys(ship * shipp,ship_subsys ** next_subsys)4374 int get_next_visible_subsys(ship *shipp, ship_subsys **next_subsys)
4375 {
4376 	int count = get_visible_sub_system_count(shipp);
4377 
4378 	// return don't try to display
4379 	if (count == 0) {
4380 		return 0;
4381 	}
4382 
4383 	// first timer
4384 	if (*next_subsys == NULL) {
4385 		*next_subsys = &shipp->subsys_list;
4386 	}
4387 
4388 	// look before wrap
4389 	for (*next_subsys = GET_NEXT(*next_subsys); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4390 		if ((*next_subsys)->system_info->subobj_num != -1) {
4391 			Update_window = 1;
4392 			return 1;
4393 		}
4394 	}
4395 
4396 	// look for first after wrap
4397 	for (*next_subsys = GET_FIRST(&shipp->subsys_list); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4398 		if ((*next_subsys)->system_info->subobj_num != -1) {
4399 			Update_window = 1;
4400 			return 1;
4401 		}
4402 	}
4403 
4404 	Int3();	// should be impossible to miss
4405 	return 0;
4406 }
4407 
get_prev_visible_subsys(ship * shipp,ship_subsys ** prev_subsys)4408 int get_prev_visible_subsys(ship *shipp, ship_subsys **prev_subsys)
4409 {
4410 	int count = get_visible_sub_system_count(shipp);
4411 
4412 	// return don't try to display
4413 	if (count == 0) {
4414 		return 0;
4415 	}
4416 
4417 	// first timer
4418 	Assert(*prev_subsys != NULL);
4419 
4420 	// look before wrap
4421 	for (*prev_subsys = GET_PREV(*prev_subsys); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4422 		if ((*prev_subsys)->system_info->subobj_num != -1) {
4423 			Update_window = 1;
4424 			return 1;
4425 		}
4426 	}
4427 
4428 	// look for first after wrap
4429 	for (*prev_subsys = GET_LAST(&shipp->subsys_list); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4430 		if ((*prev_subsys)->system_info->subobj_num != -1) {
4431 			Update_window = 1;
4432 			return 1;
4433 		}
4434 	}
4435 
4436 	Int3();	// should be impossible to miss
4437 	return 0;
4438 }
4439 
4440 // update next subsystem to view
OnNextSubsys()4441 void CFREDView::OnNextSubsys()
4442 {
4443 	object *objp;
4444 
4445 	if (cur_object_index < 0) {
4446 		OnCancelSubsys();
4447 	}
4448 
4449 	objp = &Objects[cur_object_index];
4450 
4451 	// check if cur object is ship type
4452 	if (objp->type == OBJ_SHIP) {
4453 
4454 		// check if same ship
4455 		if (Render_subsys.ship_obj == objp) {
4456 
4457 			// if already on, advance to next
4458 			if (Render_subsys.do_render) {
4459 				if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4460 					OnCancelSubsys();
4461 				}
4462 			} else {
4463 				Int3();
4464 			}
4465 		} else {
4466 			// clean up
4467 			OnCancelSubsys();
4468 
4469 			// set up new and advance to first
4470 			Render_subsys.do_render = true;
4471 			Render_subsys.ship_obj = objp;
4472 			if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4473 				OnCancelSubsys();
4474 			}
4475 		}
4476 	} else {
4477 		// not ship type
4478 		OnCancelSubsys();
4479 	}
4480 }
4481 
OnPrevSubsys()4482 void CFREDView::OnPrevSubsys()
4483 {
4484 	if (!Render_subsys.do_render) {
4485 		return;
4486 	}
4487 
4488 	if ( (cur_object_index < 0)  || (Objects[cur_object_index].type != OBJ_SHIP) || (&Objects[cur_object_index] != Render_subsys.ship_obj) ) {
4489 		OnCancelSubsys();
4490 		return;
4491 	}
4492 
4493 	if ( !get_prev_visible_subsys(&Ships[Objects[cur_object_index].instance], &Render_subsys.cur_subsys) ) {
4494 		OnCancelSubsys();
4495 	}
4496 
4497 }
4498 
OnCancelSubsys()4499 void CFREDView::OnCancelSubsys()
4500 {
4501 	Render_subsys.do_render = false;
4502 	Render_subsys.ship_obj = NULL;
4503 	Render_subsys.cur_subsys = NULL;
4504 	Update_window = 1;
4505 }
4506 
OnShowPaths()4507 void CFREDView::OnShowPaths()
4508 {
4509 	Show_paths_fred = !Show_paths_fred;
4510 	theApp.write_ini_file();
4511 	Update_window = 1;
4512 }
4513 
OnUpdateShowPaths(CCmdUI * pCmdUI)4514 void CFREDView::OnUpdateShowPaths(CCmdUI* pCmdUI)
4515 {
4516 	pCmdUI->SetCheck(Show_paths_fred);
4517 }
4518 
OnShowDockPoints()4519 void CFREDView::OnShowDockPoints()
4520 {
4521 	Show_dock_points = !Show_dock_points;
4522 	theApp.write_ini_file();
4523 	Update_window = 1;
4524 }
4525 
OnUpdateShowDockPoints(CCmdUI * pCmdUI)4526 void CFREDView::OnUpdateShowDockPoints(CCmdUI* pCmdUI)
4527 {
4528 	pCmdUI->SetCheck(Show_dock_points);
4529 }
4530 
OnDumpStats()4531 void CFREDView::OnDumpStats()
4532 {
4533 	DumpStats dlg;
4534 
4535 	dlg.DoModal();
4536 }
4537 
OnFormatFs2Open()4538 void CFREDView::OnFormatFs2Open()
4539 {
4540 	Format_fs2_open = FSO_FORMAT_STANDARD;
4541 	Format_fs2_retail = 0;
4542 	Format_fs1_retail = 0;
4543 
4544 	theApp.write_ini_file();
4545 	Update_window = 1;
4546 }
4547 
OnUpdateFormatFs2Open(CCmdUI * pCmdUI)4548 void CFREDView::OnUpdateFormatFs2Open(CCmdUI* pCmdUI)
4549 {
4550 	pCmdUI->SetCheck(Format_fs2_open == FSO_FORMAT_STANDARD);
4551 }
4552 
OnFormatFs2OpenComp()4553 void CFREDView::OnFormatFs2OpenComp()
4554 {
4555 	Format_fs2_open = FSO_FORMAT_COMPATIBILITY_MODE;
4556 	Format_fs2_retail = 0;
4557 	Format_fs1_retail = 0;
4558 
4559 	theApp.write_ini_file();
4560 	Update_window = 1;
4561 }
4562 
OnUpdateFormatFs2OpenComp(CCmdUI * pCmdUI)4563 void CFREDView::OnUpdateFormatFs2OpenComp(CCmdUI* pCmdUI)
4564 {
4565 	pCmdUI->SetCheck(Format_fs2_open == FSO_FORMAT_COMPATIBILITY_MODE);
4566 }
4567 
OnFormatFs2Retail()4568 void CFREDView::OnFormatFs2Retail()
4569 {
4570 	Format_fs2_open = FSO_FORMAT_RETAIL;
4571 	Format_fs2_retail = 1;
4572 	Format_fs1_retail = 0;
4573 
4574 	theApp.write_ini_file();
4575 	Update_window = 1;
4576 }
4577 
OnUpdateFormatFs2Retail(CCmdUI * pCmdUI)4578 void CFREDView::OnUpdateFormatFs2Retail(CCmdUI* pCmdUI)
4579 {
4580 	pCmdUI->SetCheck(Format_fs2_retail);
4581 }
4582 
OnFormatFs1Retail()4583 void CFREDView::OnFormatFs1Retail()
4584 {
4585 	Format_fs2_open = FSO_FORMAT_RETAIL;
4586 	Format_fs2_retail = 0;
4587 	Format_fs1_retail = 1;
4588 
4589 	theApp.write_ini_file();
4590 	Update_window = 1;
4591 }
4592 
OnUpdateFormatFs1Retail(CCmdUI * pCmdUI)4593 void CFREDView::OnUpdateFormatFs1Retail(CCmdUI* pCmdUI)
4594 {
4595 	pCmdUI->SetCheck(Format_fs1_retail);
4596 }
4597 
OnEditorsSetGlobalShipFlags()4598 void CFREDView::OnEditorsSetGlobalShipFlags()
4599 {
4600 	SetGlobalShipFlags dlg;
4601 
4602 	dlg.DoModal();
4603 }
4604 
OnEditorsVoiceManager()4605 void CFREDView::OnEditorsVoiceManager()
4606 {
4607 	VoiceActingManager dlg;
4608 
4609 	dlg.DoModal();
4610 }
4611 
OnEditorsFiction()4612 void CFREDView::OnEditorsFiction()
4613 {
4614 	FictionViewerDlg dlg;
4615 
4616 	dlg.DoModal();
4617 }
4618 
OnDestroy()4619 void CFREDView::OnDestroy()
4620 {
4621 	audiostream_close();
4622 	snd_close();
4623  	gr_close();
4624    	os_set_window(NULL);
4625 
4626 	CView::OnDestroy();
4627 }
4628 
OnCreate(LPCREATESTRUCT lpCreateStruct)4629 int CFREDView::OnCreate(LPCREATESTRUCT lpCreateStruct)
4630 {
4631 	if (CView::OnCreate(lpCreateStruct) == -1)
4632 		return -1;
4633 
4634 	MoveWindow(0,0,200,300,1);
4635    	os_set_window((uint)this->GetSafeHwnd());
4636    	if(fred_init() == false)
4637 		return -1;
4638 
4639 	return 0;
4640 }
4641 
OnEraseBkgnd(CDC * pDC)4642 BOOL CFREDView::OnEraseBkgnd(CDC* pDC)
4643 {
4644 	return TRUE;
4645 }
4646 
4647 
OnViewLighting()4648 void CFREDView::OnViewLighting()
4649 {
4650 
4651 	Lighting_on = !Lighting_on;
4652 }
4653 
OnUpdateViewLighting(CCmdUI * pCmdUI)4654 void CFREDView::OnUpdateViewLighting(CCmdUI* pCmdUI)
4655 {
4656 	pCmdUI->SetCheck(Lighting_on);
4657 }
4658 
OnViewFullDetail()4659 void CFREDView::OnViewFullDetail()
4660 {
4661 	FullDetail = !FullDetail;
4662 }
4663 
OnUpdateViewFullDetail(CCmdUI * pCmdUI)4664 void CFREDView::OnUpdateViewFullDetail(CCmdUI *pCmdUI)
4665 {
4666 	pCmdUI->SetCheck(FullDetail);
4667 }
4668 
DestroyWindow()4669 BOOL CFREDView::DestroyWindow()
4670 {
4671 	// TODO: Add your specialized code here and/or call the base class
4672 	return CView::DestroyWindow();
4673 }
4674 
OnShowIFF0()4675 void CFREDView::OnShowIFF0()
4676 {
4677 	OnShowIFF(0);
4678 }
4679 
OnUpdateShowIFF0(CCmdUI * pCmdUI)4680 void CFREDView::OnUpdateShowIFF0(CCmdUI* pCmdUI)
4681 {
4682 	OnUpdateShowIFF(0, pCmdUI);
4683 }
4684 
OnShowIFF1()4685 void CFREDView::OnShowIFF1()
4686 {
4687 	OnShowIFF(1);
4688 }
4689 
OnUpdateShowIFF1(CCmdUI * pCmdUI)4690 void CFREDView::OnUpdateShowIFF1(CCmdUI* pCmdUI)
4691 {
4692 	OnUpdateShowIFF(1, pCmdUI);
4693 }
4694 
OnShowIFF2()4695 void CFREDView::OnShowIFF2()
4696 {
4697 	OnShowIFF(2);
4698 }
4699 
OnUpdateShowIFF2(CCmdUI * pCmdUI)4700 void CFREDView::OnUpdateShowIFF2(CCmdUI* pCmdUI)
4701 {
4702 	OnUpdateShowIFF(2, pCmdUI);
4703 }
4704 
OnShowIFF3()4705 void CFREDView::OnShowIFF3()
4706 {
4707 	OnShowIFF(3);
4708 }
4709 
OnUpdateShowIFF3(CCmdUI * pCmdUI)4710 void CFREDView::OnUpdateShowIFF3(CCmdUI* pCmdUI)
4711 {
4712 	OnUpdateShowIFF(3, pCmdUI);
4713 }
4714 
OnShowIFF4()4715 void CFREDView::OnShowIFF4()
4716 {
4717 	OnShowIFF(4);
4718 }
4719 
OnUpdateShowIFF4(CCmdUI * pCmdUI)4720 void CFREDView::OnUpdateShowIFF4(CCmdUI* pCmdUI)
4721 {
4722 	OnUpdateShowIFF(4, pCmdUI);
4723 }
4724 
OnShowIFF5()4725 void CFREDView::OnShowIFF5()
4726 {
4727 	OnShowIFF(5);
4728 }
4729 
OnUpdateShowIFF5(CCmdUI * pCmdUI)4730 void CFREDView::OnUpdateShowIFF5(CCmdUI* pCmdUI)
4731 {
4732 	OnUpdateShowIFF(5, pCmdUI);
4733 }
4734 
OnShowIFF6()4735 void CFREDView::OnShowIFF6()
4736 {
4737 	OnShowIFF(6);
4738 }
4739 
OnUpdateShowIFF6(CCmdUI * pCmdUI)4740 void CFREDView::OnUpdateShowIFF6(CCmdUI* pCmdUI)
4741 {
4742 	OnUpdateShowIFF(6, pCmdUI);
4743 }
4744 
OnShowIFF7()4745 void CFREDView::OnShowIFF7()
4746 {
4747 	OnShowIFF(7);
4748 }
4749 
OnUpdateShowIFF7(CCmdUI * pCmdUI)4750 void CFREDView::OnUpdateShowIFF7(CCmdUI* pCmdUI)
4751 {
4752 	OnUpdateShowIFF(7, pCmdUI);
4753 }
4754 
OnShowIFF8()4755 void CFREDView::OnShowIFF8()
4756 {
4757 	OnShowIFF(8);
4758 }
4759 
OnUpdateShowIFF8(CCmdUI * pCmdUI)4760 void CFREDView::OnUpdateShowIFF8(CCmdUI* pCmdUI)
4761 {
4762 	OnUpdateShowIFF(8, pCmdUI);
4763 }
4764 
OnShowIFF9()4765 void CFREDView::OnShowIFF9()
4766 {
4767 	OnShowIFF(9);
4768 }
4769 
OnUpdateShowIFF9(CCmdUI * pCmdUI)4770 void CFREDView::OnUpdateShowIFF9(CCmdUI* pCmdUI)
4771 {
4772 	OnUpdateShowIFF(9, pCmdUI);
4773 }
4774