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(¢er, &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(¢er, &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, ¢er, &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, ¢er, &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, ¢er, &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*)¤t_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