/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "stdafx.h" #include "FRED.h" #include "FREDDoc.h" #include "FREDView.h" #include "FredRender.h" #include "cfile/cfile.h" #include "Grid.h" #include "MainFrm.h" #include "MFCGraphicsOperations.h" #include "Management.h" #include "graphics/2d.h" #include "render/3d.h" #include "object/object.h" #include "globalincs/linklist.h" #include "globalincs/vmallocator.h" #include "math/fvi.h" // For find_plane_line_intersection #include "math/vecmat.h" #include "io/key.h" #include "ai/ai.h" #include "ai/aigoals.h" #include "ship/ship.h" // for ship names #include "prop/prop.h" // for prop names #include "missioneditor/common.h" #include "MissionGoalsDlg.h" #include "MissionCutscenesDlg.h" #include "wing.h" #include "ship_select.h" #include "PlayerStartEditor.h" #include "OrientEditor.h" #include "EventEditor.h" #include "MessageEditorDlg.h" #include "starfield/starfield.h" #include "StarfieldEditor.h" #include "math/floating.h" #include "ReinforcementEditorDlg.h" #include "AsteroidEditorDlg.h" #include "CampaignTreeWnd.h" #include "DebriefingEditorDlg.h" #include "AdjustGridDlg.h" #include "ShieldSysDlg.h" #include "CmdBrief.h" #include "jumpnode/jumpnode.h" #include "DumpStats.h" #include "SetGlobalShipFlags.h" #include "VoiceActingManager.h" #include "FictionViewerDlg.h" #include "cmdline/cmdline.h" #include "object/objectdock.h" #include "species_defs/species_defs.h" #include "sound/audiostr.h" #include "mission/missiongrid.h" #include "calcrelativecoordsdlg.h" #include "reorderdlg.h" #include "musicplayerdlg.h" #include "volumetricsdlg.h" #include "customdatadlg.h" #include "customstringsdlg.h" #include "osapi/osapi.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif subsys_to_render Render_subsys; #define SHIP_TYPES 8000 #define REDUCER 100.0f #define DUP_DRAG_OF_WING 2 LOCAL int Duped_wing; int Autosave_disabled = 0; int Show_sexp_help = 1; int Show_ships = 1; int Show_starts = 1; int Show_ship_info = 1; int Show_ship_models = 1; int Show_compass = 1; int Show_dock_points = 0; int Show_paths_fred = 0; int Lighting_on = 0; int FullDetail = 0; int Selection_lock = 0; int viewpoint = 0; int view_obj; int button_down = 0; int Marked = 0, moved = 0; int on_object = -1; int Cursor_over = -1; int Dup_drag = 0; int physics_speed = 1; int physics_rot = 20; int box_marking = 0; int last_mouse_x, last_mouse_y, mouse_dx, mouse_dy; int Cur_bitmap = -1; UINT_PTR Id_select_type_waypoint = 0; UINT_PTR Id_select_type_jump_node = 0; int Hide_ship_cues = 0, Hide_wing_cues = 0; int Move_ships_when_undocking = 1; // true by default int Highlight_selectable_subsys = 0; int Point_using_uvec = 0; vec3d original_pos, saved_cam_pos; matrix bitmap_matrix_backup, saved_cam_orient = { 0.0f }; Marking_box marking_box; object_orient_pos rotation_backup[MAX_OBJECTS]; // Goober5000 (currently, FS1 retail not implemented) int Mission_save_format = FSO_FORMAT_STANDARD; // used by error checker, but needed in more than just one function. char *names[MAX_OBJECTS], flags[MAX_OBJECTS]; int obj_count = 0; int g_err = 0; SCP_vector ID_SHOW_IFF; void view_universe(int just_marked = 0); void select_objects(); void drag_rotate_save_backup(); ///////////////////////////////////////////////////////////////////////////// // CFREDView CFREDView *Fred_view_wnd = NULL; IMPLEMENT_DYNCREATE(CFREDView, CView) BEGIN_MESSAGE_MAP(CFREDView, CView) ON_MESSAGE(WM_GOODBYE, OnGoodbye) ON_MESSAGE(WM_MENU_POPUP_SHIPS, OnMenuPopupShips) ON_MESSAGE(WM_MENU_POPUP_EDIT, OnMenuPopupEdit) //{{AFX_MSG_MAP(CFREDView) ON_COMMAND(ID_VIEW_GRID, OnViewGrid) ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid) ON_COMMAND(ID_SHOW_WAYPOINTS, OnViewWaypoints) ON_UPDATE_COMMAND_UI(ID_SHOW_WAYPOINTS, OnUpdateViewWaypoints) ON_WM_LBUTTONDOWN() ON_COMMAND(ID_EDITORS_SHIPS, OnEditorsShips) ON_COMMAND(ID_EDITORS_PROPS, OnEditorsProps) ON_WM_KEYDOWN() ON_WM_KEYUP() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_SIZE() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_MBUTTONDOWN() ON_WM_MBUTTONUP() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_MOUSEWHEEL() ON_COMMAND(ID_MISCSTUFF_SHOWSHIPSASICONS, OnMiscstuffShowshipsasicons) ON_WM_CONTEXTMENU() ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnEditPopupShowShipIcons) ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnUpdateEditPopupShowShipIcons) ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnEditPopupShowShipModels) ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnUpdateEditPopupShowShipModels) ON_COMMAND(ID_MISC_STATISTICS, OnMiscStatistics) ON_COMMAND(ID_EDIT_POPUP_SHOW_COMPASS, OnEditPopupShowCompass) ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_COMPASS, OnUpdateEditPopupShowCompass) ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_EXTERNAL, OnUpdateChangeViewpointExternal) ON_COMMAND(ID_CHANGE_VIEWPOINT_EXTERNAL, OnChangeViewpointExternal) ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_FOLLOW, OnUpdateChangeViewpointFollow) ON_COMMAND(ID_CHANGE_VIEWPOINT_FOLLOW, OnChangeViewpointFollow) ON_COMMAND(ID_OUTLINE_LOD_0, OnOutlineLod0) ON_UPDATE_COMMAND_UI(ID_OUTLINE_LOD_0, OnUpdateOutlineLod0) ON_COMMAND(ID_OUTLINE_LOD_1, OnOutlineLod1) ON_UPDATE_COMMAND_UI(ID_OUTLINE_LOD_1, OnUpdateOutlineLod1) ON_COMMAND(ID_OUTLINE_LOD_2, OnOutlineLod2) ON_UPDATE_COMMAND_UI(ID_OUTLINE_LOD_2, OnUpdateOutlineLod2) ON_COMMAND(ID_OUTLINE_LOD_3, OnOutlineLod3) ON_UPDATE_COMMAND_UI(ID_OUTLINE_LOD_3, OnUpdateOutlineLod3) ON_COMMAND(ID_OUTLINE_LOD_4, OnOutlineLod4) ON_UPDATE_COMMAND_UI(ID_OUTLINE_LOD_4, OnUpdateOutlineLod4) ON_COMMAND(ID_LABEL_FONT_SCALE_50, OnLabelFontScale50) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_50, OnUpdateLabelFontScale50) ON_COMMAND(ID_LABEL_FONT_SCALE_75, OnLabelFontScale75) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_75, OnUpdateLabelFontScale75) ON_COMMAND(ID_LABEL_FONT_SCALE_100, OnLabelFontScale100) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_100, OnUpdateLabelFontScale100) ON_COMMAND(ID_LABEL_FONT_SCALE_125, OnLabelFontScale125) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_125, OnUpdateLabelFontScale125) ON_COMMAND(ID_LABEL_FONT_SCALE_150, OnLabelFontScale150) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_150, OnUpdateLabelFontScale150) ON_COMMAND(ID_LABEL_FONT_SCALE_200, OnLabelFontScale200) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_200, OnUpdateLabelFontScale200) ON_COMMAND(ID_LABEL_FONT_SCALE_250, OnLabelFontScale250) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_250, OnUpdateLabelFontScale250) ON_COMMAND(ID_LABEL_FONT_SCALE_300, OnLabelFontScale300) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_300, OnUpdateLabelFontScale300) ON_COMMAND(ID_LABEL_FONT_SCALE_350, OnLabelFontScale350) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_350, OnUpdateLabelFontScale350) ON_COMMAND(ID_LABEL_FONT_SCALE_400, OnLabelFontScale400) ON_UPDATE_COMMAND_UI(ID_LABEL_FONT_SCALE_400, OnUpdateLabelFontScale400) ON_COMMAND(ID_EDITORS_GOALS, OnEditorsGoals) ON_COMMAND(ID_EDITORS_CUTSCENES, OnEditorsCutscenes) ON_COMMAND(ID_SPEED1, OnSpeed1) ON_COMMAND(ID_SPEED2, OnSpeed2) ON_COMMAND(ID_SPEED5, OnSpeed5) ON_COMMAND(ID_SPEED10, OnSpeed10) ON_UPDATE_COMMAND_UI(ID_SPEED1, OnUpdateSpeed1) ON_COMMAND(ID_SPEED3, OnSpeed3) ON_COMMAND(ID_SPEED8, OnSpeed8) ON_COMMAND(ID_ROT1, OnRot1) ON_COMMAND(ID_ROT2, OnRot2) ON_COMMAND(ID_ROT3, OnRot3) ON_COMMAND(ID_ROT4, OnRot4) ON_COMMAND(ID_ROT5, OnRot5) ON_UPDATE_COMMAND_UI(ID_SPEED2, OnUpdateSpeed2) ON_UPDATE_COMMAND_UI(ID_SPEED3, OnUpdateSpeed3) ON_UPDATE_COMMAND_UI(ID_SPEED5, OnUpdateSpeed5) ON_UPDATE_COMMAND_UI(ID_SPEED8, OnUpdateSpeed8) ON_UPDATE_COMMAND_UI(ID_SPEED10, OnUpdateSpeed10) ON_UPDATE_COMMAND_UI(ID_ROT1, OnUpdateRot1) ON_UPDATE_COMMAND_UI(ID_ROT2, OnUpdateRot2) ON_UPDATE_COMMAND_UI(ID_ROT3, OnUpdateRot3) ON_UPDATE_COMMAND_UI(ID_ROT4, OnUpdateRot4) ON_UPDATE_COMMAND_UI(ID_ROT5, OnUpdateRot5) ON_COMMAND(ID_CONTROL_MODE_CAMERA, OnControlModeCamera) ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_CAMERA, OnUpdateControlModeCamera) ON_COMMAND(ID_CONTROL_MODE_SHIP, OnControlModeShip) ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_SHIP, OnUpdateControlModeShip) ON_COMMAND(ID_SHOW_GRID_POSITIONS, OnShowGridPositions) ON_UPDATE_COMMAND_UI(ID_SHOW_GRID_POSITIONS, OnUpdateShowGridPositions) ON_COMMAND(ID_SHOW_COORDINATES, OnShowCoordinates) ON_UPDATE_COMMAND_UI(ID_SHOW_COORDINATES, OnUpdateShowCoordinates) ON_COMMAND(ID_SPEED50, OnSpeed50) ON_UPDATE_COMMAND_UI(ID_SPEED50, OnUpdateSpeed50) ON_COMMAND(ID_SPEED100, OnSpeed100) ON_UPDATE_COMMAND_UI(ID_SPEED100, OnUpdateSpeed100) ON_COMMAND(ID_SPEED500, OnSpeed500) ON_UPDATE_COMMAND_UI(ID_SPEED500, OnUpdateSpeed500) ON_COMMAND(ID_SPEED1000, OnSpeed1000) ON_UPDATE_COMMAND_UI(ID_SPEED1000, OnUpdateSpeed1000) ON_COMMAND(ID_SELECT, OnSelect) ON_UPDATE_COMMAND_UI(ID_SELECT, OnUpdateSelect) ON_COMMAND(ID_SELECT_AND_MOVE, OnSelectAndMove) ON_UPDATE_COMMAND_UI(ID_SELECT_AND_MOVE, OnUpdateSelectAndMove) ON_COMMAND(ID_SELECT_AND_ROTATE, OnSelectAndRotate) ON_UPDATE_COMMAND_UI(ID_SELECT_AND_ROTATE, OnUpdateSelectAndRotate) ON_COMMAND(ID_CONSTRAIN_X, OnConstrainX) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_X, OnUpdateConstrainX) ON_COMMAND(ID_CONSTRAIN_Y, OnConstrainY) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Y, OnUpdateConstrainY) ON_COMMAND(ID_CONSTRAIN_Z, OnConstrainZ) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Z, OnUpdateConstrainZ) ON_COMMAND(ID_CONSTRAIN_XZ, OnConstrainXz) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XZ, OnUpdateConstrainXz) ON_COMMAND(ID_SELECTION_LOCK, OnSelectionLock) ON_UPDATE_COMMAND_UI(ID_SELECTION_LOCK, OnUpdateSelectionLock) ON_WM_LBUTTONDBLCLK() ON_COMMAND(ID_DOUBLE_FINE_GRIDLINES, OnDoubleFineGridlines) ON_UPDATE_COMMAND_UI(ID_DOUBLE_FINE_GRIDLINES, OnUpdateDoubleFineGridlines) ON_COMMAND(ID_SHOW_DISTANCES, OnShowDistances) ON_UPDATE_COMMAND_UI(ID_SHOW_DISTANCES, OnUpdateShowDistances) ON_COMMAND(ID_UNIVERSAL_HEADING, OnUniversalHeading) ON_UPDATE_COMMAND_UI(ID_UNIVERSAL_HEADING, OnUpdateUniversalHeading) ON_COMMAND(ID_FLYING_CONTROLS, OnFlyingControls) ON_UPDATE_COMMAND_UI(ID_FLYING_CONTROLS, OnUpdateFlyingControls) ON_COMMAND(ID_ROTATE_LOCALLY, OnRotateLocally) ON_UPDATE_COMMAND_UI(ID_ROTATE_LOCALLY, OnUpdateRotateLocally) ON_COMMAND(ID_CONSTRAIN_XY, OnConstrainXy) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XY, OnUpdateConstrainXy) ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_YZ, OnUpdateConstrainYz) ON_COMMAND(ID_CONSTRAIN_YZ, OnConstrainYz) ON_COMMAND(ID_SELECT_LIST, OnSelectList) ON_COMMAND(ID_ZOOM_EXTENTS, OnZoomExtents) ON_COMMAND(ID_ZOOM_SELECTED, OnZoomSelected) ON_UPDATE_COMMAND_UI(ID_ZOOM_SELECTED, OnUpdateZoomSelected) ON_COMMAND(ID_FORM_WING, OnFormWing) ON_UPDATE_COMMAND_UI(ID_FORM_WING, OnUpdateFormWing) ON_COMMAND(ID_DISBAND_WING, OnDisbandWing) ON_UPDATE_COMMAND_UI(ID_DISBAND_WING, OnUpdateDisbandWing) ON_COMMAND(ID_SHOW_HORIZON, OnShowHorizon) ON_UPDATE_COMMAND_UI(ID_SHOW_HORIZON, OnUpdateShowHorizon) ON_COMMAND(ID_EDITORS_WING, OnEditorsWing) ON_COMMAND(ID_EDITORS_PLAYER, OnEditorsPlayer) ON_COMMAND(ID_EDITORS_ORIENT, OnEditorsOrient) ON_COMMAND(ID_EDITORS_EVENTS, OnEditorsEvents) ON_UPDATE_COMMAND_UI(ID_EDITORS_ORIENT, OnUpdateEditorsOrient) ON_COMMAND(ID_EDITORS_MESSAGE, OnEditorsMessage) ON_COMMAND(ID_EDITORS_STARFIELD, OnEditorsStarfield) ON_COMMAND(ID_EDITORS_BG_BITMAPS, OnEditorsBgBitmaps) ON_COMMAND(ID_EDITORS_VOLUMETRICS, OnEditorsVolumetrics) ON_COMMAND(ID_EDITORS_REINFORCEMENT, OnEditorsReinforcement) ON_COMMAND(ID_ERROR_CHECKER, OnErrorChecker) ON_COMMAND(ID_EDITORS_WAYPOINT, OnEditorsWaypoint) ON_COMMAND(ID_EDITORS_JUMPNODE, OnEditorsJumpnode) ON_COMMAND(ID_VIEW_OUTLINES, OnViewOutlines) ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINES, OnUpdateViewOutlines) ON_COMMAND(ID_VIEW_OUTLINES_ON_SELECTED, OnViewOutlinesOnSelected) ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINES_ON_SELECTED, OnUpdateViewOutlinesOnSelected) ON_COMMAND(ID_VIEW_OUTLINE_AT_WARPIN, OnViewOutlineAtWarpin) ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINE_AT_WARPIN, OnUpdateViewOutlineAtWarpin) ON_COMMAND(ID_MISC_ROTATE_SELECTION_MIDPOINT, OnMiscRotateSelectionMidpoint) ON_UPDATE_COMMAND_UI(ID_MISC_ROTATE_SELECTION_MIDPOINT, OnUpdateMiscRotateSelectionMidpoint) ON_COMMAND(ID_ALWAYS_SAVE_DISPLAY_NAMES, OnAlwaysSaveDisplayNames) ON_UPDATE_COMMAND_UI(ID_ALWAYS_SAVE_DISPLAY_NAMES, OnUpdateAlwaysSaveDisplayNames) ON_COMMAND(ID_ERROR_CHECKER_CHECKS_POTENTIAL_ISSUES, OnErrorCheckerChecksPotentialIssues) ON_UPDATE_COMMAND_UI(ID_ERROR_CHECKER_CHECKS_POTENTIAL_ISSUES, OnUpdateErrorCheckerChecksPotentialIssues) ON_COMMAND(ID_CLASSIC_MENU_LAYOUT, OnClassicMenuLayout) ON_UPDATE_COMMAND_UI(ID_CLASSIC_MENU_LAYOUT, OnUpdateClassicMenuLayout) ON_UPDATE_COMMAND_UI(ID_NEW_SHIP_TYPE, OnUpdateNewShipType) ON_COMMAND(ID_SHOW_STARFIELD, OnShowStarfield) ON_UPDATE_COMMAND_UI(ID_SHOW_STARFIELD, OnUpdateShowStarfield) ON_COMMAND(ID_ASTEROID_EDITOR, OnAsteroidEditor) ON_COMMAND(ID_RUN_FREESPACE, OnRunFreeSpace) ON_COMMAND(ID_EDITOR_CAMPAIGN, OnEditorCampaign) ON_COMMAND(ID_SHOW_SHIPS, OnShowShips) ON_UPDATE_COMMAND_UI(ID_SHOW_SHIPS, OnUpdateShowShips) ON_COMMAND(ID_SHOW_STARTS, OnShowStarts) ON_UPDATE_COMMAND_UI(ID_SHOW_STARTS, OnUpdateShowStarts) ON_COMMAND(ID_SHOW_IFF_0, OnShowIFF0) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_0, OnUpdateShowIFF0) ON_COMMAND(ID_SHOW_IFF_1, OnShowIFF1) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_1, OnUpdateShowIFF1) ON_COMMAND(ID_SHOW_IFF_2, OnShowIFF2) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_2, OnUpdateShowIFF2) ON_COMMAND(ID_SHOW_IFF_3, OnShowIFF3) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_3, OnUpdateShowIFF3) ON_COMMAND(ID_SHOW_IFF_4, OnShowIFF4) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_4, OnUpdateShowIFF4) ON_COMMAND(ID_SHOW_IFF_5, OnShowIFF5) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_5, OnUpdateShowIFF5) ON_COMMAND(ID_SHOW_IFF_6, OnShowIFF6) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_6, OnUpdateShowIFF6) ON_COMMAND(ID_SHOW_IFF_7, OnShowIFF7) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_7, OnUpdateShowIFF7) ON_COMMAND(ID_SHOW_IFF_8, OnShowIFF8) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_8, OnUpdateShowIFF8) ON_COMMAND(ID_SHOW_IFF_9, OnShowIFF9) ON_UPDATE_COMMAND_UI(ID_SHOW_IFF_9, OnUpdateShowIFF9) ON_COMMAND(ID_TOGGLE_VIEWPOINT, OnToggleViewpoint) ON_COMMAND(ID_REVERT, OnRevert) ON_UPDATE_COMMAND_UI(ID_REVERT, OnUpdateRevert) ON_WM_SETCURSOR() ON_COMMAND(ID_HIDE_MARKED_OBJECTS, OnHideMarkedObjects) ON_COMMAND(ID_SHOW_HIDDEN_OBJECTS, OnShowHiddenObjects) ON_COMMAND(ID_EDIT_LOCK_MARKED_OBJECTS, OnLockMarkedObjects) ON_COMMAND(ID_EDIT_UNLOCK_ALL_OBJECTS, OnUnlockAllObjects) ON_COMMAND(ID_EDIT_UNDO, OnEditUndo) ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo) ON_COMMAND(ID_EDITORS_BRIEFING, OnEditorsBriefing) ON_COMMAND(ID_EDITORS_DEBRIEFING, OnEditorsDebriefing) ON_COMMAND(ID_SAVE_CAMERA, OnSaveCamera) ON_COMMAND(ID_RESTORE_CAMERA, OnRestoreCamera) ON_UPDATE_COMMAND_UI(ID_RESTORE_CAMERA, OnUpdateRestoreCamera) ON_COMMAND(ID_SHOW_SEXP_HELP, OnShowSexpHelp) ON_UPDATE_COMMAND_UI(ID_SHOW_SEXP_HELP, OnUpdateShowSexpHelp) ON_COMMAND(ID_LOOKAT_OBJ, OnLookatObj) ON_UPDATE_COMMAND_UI(ID_LOOKAT_OBJ, OnUpdateLookatObj) ON_COMMAND(ID_EDITORS_ADJUST_GRID, OnEditorsAdjustGrid) ON_COMMAND(ID_CALC_RELATIVE_COORDS, OnCalcRelativeCoords) ON_COMMAND(ID_REORDER, OnReorder) ON_COMMAND(ID_MUSIC_PLAYER, OnMusicPlayer) ON_COMMAND(ID_EDITORS_SHIELD_SYS, OnEditorsShieldSys) ON_COMMAND(ID_LEVEL_OBJ, OnLevelObj) ON_COMMAND(ID_ALIGN_OBJ, OnAlignObj) ON_COMMAND(ID_CONTROL_OBJ, OnControlObj) ON_COMMAND(ID_NEXT_OBJ, OnNextObj) ON_COMMAND(ID_PREV_OBJ, OnPrevObj) ON_COMMAND(ID_EDIT_CLONEMARKEDOBJECTS, OnEditCloneMarkedObjects) ON_COMMAND(ID_EDIT_DELETE_WING, OnEditDeleteWing) ON_COMMAND(ID_MARK_WING, OnMarkWing) ON_UPDATE_COMMAND_UI(ID_CONTROL_OBJ, OnUpdateControlObj) ON_COMMAND(ID_EDIT_DELETE, OnEditDelete) ON_COMMAND(ID_AA_GRIDLINES, OnAaGridlines) ON_UPDATE_COMMAND_UI(ID_AA_GRIDLINES, OnUpdateAaGridlines) ON_COMMAND(ID_EDITORS_CMD_BRIEF, OnCmdBrief) ON_COMMAND(ID_DISABLE_UNDO, OnDisableUndo) ON_UPDATE_COMMAND_UI(ID_DISABLE_UNDO, OnUpdateDisableUndo) ON_UPDATE_COMMAND_UI(ID_EDITORS_CMD_BRIEF, OnUpdateCmdBrief) ON_COMMAND(ID_NEXT_SUBSYS, OnNextSubsys) ON_COMMAND(ID_PREV_SUBSYS, OnPrevSubsys) ON_COMMAND(ID_CANCEL_SUBSYS, OnCancelSubsys) ON_COMMAND(ID_DUMP_STATS, OnDumpStats) ON_COMMAND(ID_SHOW_PATHS, OnShowPaths) ON_UPDATE_COMMAND_UI(ID_SHOW_PATHS, OnUpdateShowPaths) ON_COMMAND(ID_SHOW_DOCK_POINTS, OnShowDockPoints) ON_UPDATE_COMMAND_UI(ID_SHOW_DOCK_POINTS, OnUpdateShowDockPoints) ON_COMMAND(ID_FORMAT_FS2_OPEN, OnFormatFs2Open) ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_OPEN, OnUpdateFormatFs2Open) ON_COMMAND(ID_FORMAT_FS2_OPEN_COMP, OnFormatFs2OpenComp) ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_OPEN_COMP, OnUpdateFormatFs2OpenComp) ON_COMMAND(ID_FORMAT_FS2_RETAIL, OnFormatFs2Retail) ON_UPDATE_COMMAND_UI(ID_FORMAT_FS2_RETAIL, OnUpdateFormatFs2Retail) ON_COMMAND(ID_FORMAT_FS1_RETAIL, OnFormatFs1Retail) ON_UPDATE_COMMAND_UI(ID_FORMAT_FS1_RETAIL, OnUpdateFormatFs1Retail) ON_COMMAND(ID_MISC_MOVESHIPSWHENUNDOCKING, OnMoveShipsWhenUndocking) ON_UPDATE_COMMAND_UI(ID_MISC_MOVESHIPSWHENUNDOCKING, OnUpdateMoveShipsWhenUndocking) ON_COMMAND(ID_MISC_POINTUSINGUVEC, OnPointUsingUvec) ON_UPDATE_COMMAND_UI(ID_MISC_POINTUSINGUVEC, OnUpdatePointUsingUvec) ON_COMMAND(ID_HIGHLIGHT_SUBSYS, OnHighlightSubsys) ON_UPDATE_COMMAND_UI(ID_HIGHLIGHT_SUBSYS, OnUpdateHighlightSubsys) ON_COMMAND(ID_EDITORS_SET_GLOBAL_SHIP_FLAGS, OnEditorsSetGlobalShipFlags) ON_COMMAND(ID_EDITORS_VOICE, OnEditorsVoiceManager) ON_COMMAND(ID_EDITORS_FICTION, OnEditorsFiction) ON_WM_DESTROY() ON_WM_CREATE() ON_WM_ERASEBKGND() ON_COMMAND(ID_VIEW_LIGHTING, OnViewLighting) ON_UPDATE_COMMAND_UI(ID_VIEW_LIGHTING, OnUpdateViewLighting) ON_COMMAND(ID_VIEW_FULL_DETAIL, OnViewFullDetail) ON_UPDATE_COMMAND_UI(ID_VIEW_FULL_DETAIL, OnUpdateViewFullDetail) //}}AFX_MSG_MAP ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) ON_COMMAND_RANGE(ID_GROUP1, ID_GROUP9, OnGroup) ON_COMMAND_RANGE(ID_SET_GROUP1, ID_SET_GROUP9, OnSetGroup) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFREDView construction/destruction CFREDView::CFREDView() { //m_ConfirmDeleting = TRUE; //m_ShowCapitalShips = TRUE; //m_ShowElevations = TRUE; //m_ShowFighters = TRUE; //m_ShowGrid = TRUE; //m_ShowMiscObjects = TRUE; //m_ShowPlanets = TRUE; //m_ShowWaypoints = TRUE; // this is stupid ID_SHOW_IFF.push_back(ID_SHOW_IFF_0); ID_SHOW_IFF.push_back(ID_SHOW_IFF_1); ID_SHOW_IFF.push_back(ID_SHOW_IFF_2); ID_SHOW_IFF.push_back(ID_SHOW_IFF_3); ID_SHOW_IFF.push_back(ID_SHOW_IFF_4); ID_SHOW_IFF.push_back(ID_SHOW_IFF_5); ID_SHOW_IFF.push_back(ID_SHOW_IFF_6); ID_SHOW_IFF.push_back(ID_SHOW_IFF_7); ID_SHOW_IFF.push_back(ID_SHOW_IFF_8); ID_SHOW_IFF.push_back(ID_SHOW_IFF_9); m_pGDlg = new CGrid(this); //if (!(int errno = gr_init(640, 480, 32))) // Error(LOCATION, "Hey, gr_init failed! Error code = %i", errno); Fred_view_wnd = this; } CFREDView::~CFREDView() { delete m_pGDlg; } BOOL CFREDView::PreCreateWindow(CREATESTRUCT& cs) { BOOL casperl; casperl = CView::PreCreateWindow(cs); cs.y = 0; // doesn't seem to do anything. :( // other miscellaneous initializations if (Cmdline_mod) cfile_chdir(Cmdline_mod); cfile_chdir("data\\missions"); set_physics_controls(); return casperl; } ///////////////////////////////////////////////////////////////////////////// // CFREDView drawing void CFREDView::OnDraw(CDC* pDC) { CRect clip; CFREDDoc* pDoc = GetDocument(); Assert(pDoc != nullptr); Update_window = 1; } ///////////////////////////////////////////////////////////////////////////// // CFREDView printing BOOL CFREDView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CFREDView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CFREDView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CFREDView diagnostics #ifdef _DEBUG void CFREDView::AssertValid() const { CView::AssertValid(); } void CFREDView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CFREDDoc* CFREDView::GetDocument() // non-debug version is inline { Assert(m_pDocument->IsKindOf(RUNTIME_CLASS(CFREDDoc))); return (CFREDDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CFREDView message handlers void CFREDView::OnViewGrid() { Show_grid = !Show_grid; Update_window = 1; } void CFREDView::OnUpdateViewGrid(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_grid); } void CFREDView::OnViewWaypoints() { Show_waypoints = !Show_waypoints; correct_marking(); Update_window = 1; } void CFREDView::OnUpdateViewWaypoints(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_waypoints); } int duplicate_marked_objects() { int z, cobj, flag; object *objp, *ptr; cobj = Duped_wing = -1; flag = 0; int duping_waypoint_list = -1; objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if (objp->flags[Object::Object_Flags::Marked]) { if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) { z = Ships[objp->instance].wingnum; if (!flag) Duped_wing = z; else if (Duped_wing != z) Duped_wing = -1; } else { Duped_wing = -1; } // make sure we dup as many waypoint lists as we have if (objp->type == OBJ_WAYPOINT) { int this_list = calc_waypoint_list_index(objp->instance); if (duping_waypoint_list != this_list) { dup_object(nullptr); // reset waypoint list duping_waypoint_list = this_list; } } flag = 1; z = dup_object(objp); if (z == -1) { cobj = -1; break; } if (cur_object_index == OBJ_INDEX(objp) ) cobj = z; } objp = GET_NEXT(objp); } obj_merge_created_list(); // I think this code is to catch the case where an object wasn't created for whatever reason; // in this case just delete the remaining objects we just created if (cobj == -1) { objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { ptr = GET_NEXT(objp); if (objp->flags [Object::Object_Flags::Temp_marked]) delete_object(objp); objp = ptr; } button_down = 0; return -1; } unmark_all(); objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->flags [Object::Object_Flags::Temp_marked]) { objp->flags.remove(Object::Object_Flags::Temp_marked); mark_object(OBJ_INDEX(objp)); } objp = GET_NEXT(objp); } set_cur_object_index(cobj); return 0; } #define MAX_MOVE_DISTANCE 25.0f // If cur_object_index references a valid object, drag it from its current // location to the new cursor location specified by "point". // It is dragged relative to the main grid. Its y coordinate is not changed. // Return value: 0/1 = didn't/did move object all the way to goal. int drag_objects() { int rval = 1; float r; float distance_moved = 0.0f; vec3d cursor_dir, int_pnt; vec3d movement_vector; vec3d obj; vec3d vec1, vec2; object *objp; // starfield_bitmaps *bmp; /* if (Bg_bitmap_dialog) { if (Cur_bitmap < 0) return -1; bmp = &Starfield_bitmaps[Cur_bitmap]; if (Single_axis_constraint && Constraint.z) { bmp->dist *= 1.0f + mouse_dx / -800.0f; calculate_bitmap_points(bmp, 0.0f); } else { g3_point_to_vec_delayed(&bmp->m.fvec, marking_box.x2, marking_box.y2); vm_orthogonalize_matrix(&bmp->m); calculate_bitmap_points(bmp, 0.0f); } return rval; } */ // Do not move ships that we are currently centered around (Lookat_mode). The vector math will start going haywire and return NAN if (!query_valid_object() || Lookat_mode) return -1; if ((Dup_drag == 1) && (Briefing_dialog)) Dup_drag = 0; if (Dup_drag == 1) { if (duplicate_marked_objects() < 0) return -1; if (Duped_wing != -1) Dup_drag = DUP_DRAG_OF_WING; // indication for later that we duped objects in a wing else Dup_drag = 0; drag_rotate_save_backup(); set_modified(); Update_window = 1; } objp = &Objects[cur_object_index]; Assert(objp->type != OBJ_NONE); obj = int_pnt = objp->pos; // Get 3d vector specified by mouse cursor location. g3_point_to_vec_delayed(&cursor_dir, marking_box.x2, marking_box.y2); if (Single_axis_constraint) { // if (fvi_ray_plane(&int_pnt, &obj, &view_orient.fvec, &view_pos, &cursor_dir, 0.0f) >= 0.0f ) { // vm_vec_add(&p1, &obj, &Constraint); // find_nearest_point_on_line(&nearest_point, &obj, &p1, &int_pnt); // int_pnt = nearest_point; // distance_moved = vm_vec_dist(&obj, &int_pnt); // } vec3d tmpAnticonstraint = Anticonstraint; vec3d tmpObject = obj; tmpAnticonstraint.xyz.x = 0.0f; r = fvi_ray_plane(&int_pnt, &tmpObject, &tmpAnticonstraint, &view_pos, &cursor_dir, 0.0f); // If intersected behind viewer, don't move. Too confusing, not what user wants. vm_vec_sub(&vec1, &int_pnt, &view_pos); vm_vec_sub(&vec2, &obj, &view_pos); if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f)) { vec3d tmp1; vm_vec_sub( &tmp1, &int_pnt, &obj ); tmp1.xyz.x *= Constraint.xyz.x; tmp1.xyz.y *= Constraint.xyz.y; tmp1.xyz.z *= Constraint.xyz.z; vm_vec_add( &int_pnt, &obj, &tmp1 ); distance_moved = vm_vec_dist(&obj, &int_pnt); } } else { // Move in x-z plane, defined by grid. Preserve height. r = fvi_ray_plane(&int_pnt, &obj, &Anticonstraint, &view_pos, &cursor_dir, 0.0f); // If intersected behind viewer, don't move. Too confusing, not what user wants. vm_vec_sub(&vec1, &int_pnt, &view_pos); vm_vec_sub(&vec2, &obj, &view_pos); if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f)) distance_moved = vm_vec_dist(&obj, &int_pnt); } // If moved too far, then move max distance along vector. vm_vec_sub(&movement_vector, &int_pnt, &obj); /* if (distance_moved > MAX_MOVE_DISTANCE) { vm_vec_normalize(&movement_vector); vm_vec_scale(&movement_vector, MAX_MOVE_DISTANCE); } */ if (distance_moved) { objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if (objp->flags[Object::Object_Flags::Marked]) { vm_vec_add(&objp->pos, &objp->pos, &movement_vector); if (objp->type == OBJ_WAYPOINT) { waypoint *wpt = find_waypoint_with_instance(objp->instance); Assert(wpt != NULL); wpt->set_pos(&objp->pos); } } objp = GET_NEXT(objp); } objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->flags[Object::Object_Flags::Marked]) object_moved(objp); objp = GET_NEXT(objp); } } if (Briefing_dialog) Briefing_dialog->update_positions(); set_modified(); return rval; } void drag_rotate_save_backup() { object *objp; /* if (Cur_bitmap != -1) bitmap_matrix_backup = Starfield_bitmaps[Cur_bitmap].m; */ objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if (objp->flags[Object::Object_Flags::Marked]) { rotation_backup[OBJ_INDEX(objp)].pos = objp->pos; rotation_backup[OBJ_INDEX(objp)].orient = objp->orient; } objp = GET_NEXT(objp); } } int drag_rotate_objects() { int rval = 1; vec3d int_pnt, obj; angles a; matrix leader_orient, leader_transpose, tmp, newmat, rotmat; object *leader, *objp; // starfield_bitmaps *bmp; Update_window = 1; /* if (Bg_bitmap_dialog) { if (Cur_bitmap < 0) return -1; bmp = &Starfield_bitmaps[Cur_bitmap]; calculate_bitmap_points(bmp, mouse_dx / -300.0f); return rval; } */ if (!query_valid_object()){ return -1; } objp = &Objects[cur_object_index]; Assert(objp->type != OBJ_NONE); obj = int_pnt = objp->pos; memset(&a, 0, sizeof(angles)); if (Single_axis_constraint) { if (Constraint.xyz.x) a.p = mouse_dy / REDUCER; else if (Constraint.xyz.y) a.h = mouse_dx / REDUCER; else if (Constraint.xyz.z) a.b = -mouse_dx / REDUCER; } else { if (!Constraint.xyz.x) { // yz a.b = -mouse_dx / REDUCER; a.h = mouse_dy / REDUCER; } else if (!Constraint.xyz.y) { // xz a.p = mouse_dy / REDUCER; a.b = -mouse_dx / REDUCER; } else if (!Constraint.xyz.z) { // xy a.p = mouse_dy / REDUCER; a.h = mouse_dx / REDUCER; } } leader = &Objects[cur_object_index]; leader_orient = leader->orient; // save original orientation vm_copy_transpose(&leader_transpose, &leader_orient); vm_angles_2_matrix(&rotmat, &a); vm_matrix_x_matrix(&newmat, &leader->orient, &rotmat); leader->orient = newmat; objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if ((objp->flags[Object::Object_Flags::Marked]) && (cur_object_index != OBJ_INDEX(objp) )) { if (Group_rotate) { matrix rot_trans; vec3d tmpv1, tmpv2; // change rotation matrix to rotate in opposite direction. This rotation // matrix is what the leader ship has rotated by. vm_copy_transpose(&rot_trans, &rotmat); // get point relative to our point of rotation (make POR the origin). vm_vec_sub(&tmpv1, &objp->pos, &leader->pos); // convert point from real-world coordinates to leader's relative coordinate // system (z=forward vec, y=up vec, x=right vec vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient); // now rotate the point by the transpose from above. vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans); // convert point back into real-world coordinates vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose); // and move origin back to real-world origin. Object is now at its correct // position. vm_vec_add(&objp->pos, &leader->pos, &tmpv2); // Now fix the object's orientation to what it should be. vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat); vm_orthogonalize_matrix(&tmp); // safety check objp->orient = tmp; } else { vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat); objp->orient = tmp; } } objp = GET_NEXT(objp); } objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->flags[Object::Object_Flags::Marked]) object_moved(objp); objp = GET_NEXT(objp); } set_modified(); return rval; } void cancel_drag() { Update_window = 1; /* if (Bg_bitmap_dialog) { Assert(!vm_check_matrix_for_zeros(&bitmap_matrix_backup)); Starfield_bitmaps[Cur_bitmap].m = bitmap_matrix_backup; calculate_bitmap_points(&Starfield_bitmaps[Cur_bitmap], 0.0f); button_down = box_marking = 0; Update_window = 1; return; } */ if (button_down) { if (Editing_mode == 1) { vec3d movement_vector; object *objp; if (query_valid_object()) { objp = &Objects[cur_object_index]; Assert(objp->type != OBJ_NONE); vm_vec_sub(&movement_vector, &original_pos, &objp->pos); objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if (objp->flags[Object::Object_Flags::Marked]) vm_vec_add(&objp->pos, &objp->pos, &movement_vector); objp = GET_NEXT(objp); } } } else if (Editing_mode == 2) { object *objp; objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { Assert(objp->type != OBJ_NONE); if (objp->flags[Object::Object_Flags::Marked]) { int obj_index = OBJ_INDEX(objp); if(!IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.rvec) && !IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.uvec) && !IS_VEC_NULL(&rotation_backup[obj_index].orient.vec.fvec)){ objp->pos = rotation_backup[obj_index].pos; objp->orient = rotation_backup[obj_index].orient; } } objp = GET_NEXT(objp); } } } button_down = box_marking = 0; if (Briefing_dialog) Briefing_dialog->update_positions(); } void CFREDView::OnLButtonDown(UINT nFlags, CPoint point) { // RT point int waypoint_instance = -1; if (!Fred_active) { CView::OnLButtonDown(nFlags, point); return; } if (cur_waypoint != NULL) { Assert(cur_waypoint_list != NULL); waypoint_instance = Objects[cur_waypoint->get_objnum()].instance; } marking_box.x1 = point.x; marking_box.y1 = point.y; Dup_drag = 0; on_object = select_object(point.x, point.y); button_down = 1; SetCapture(); drag_rotate_save_backup(); if (nFlags & MK_CONTROL) { // add a new object bool shift_down = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0; if (shift_down) { Selection_lock = 0; // force off selection lock on_object = create_object_on_grid(waypoint_instance, true); } else { if (!Bg_bitmap_dialog) { if (on_object == -1) { Selection_lock = 0; // force off selection lock on_object = create_object_on_grid(waypoint_instance); } else Dup_drag = 1; } else { /* Selection_lock = 0; // force off selection lock on_object = Cur_bitmap = create_bg_bitmap(); Bg_bitmap_dialog->update_data(); Update_window = 1; if (Cur_bitmap == -1) MessageBox("Background bitmap limit reached.\nCan't add more."); */ } } } else if (!Selection_lock) { if (Bg_bitmap_dialog) { Cur_bitmap = on_object; Bg_bitmap_dialog -> update_data(); } else if ((nFlags & MK_SHIFT) || (on_object == -1) || !(Objects[on_object].flags[Object::Object_Flags::Marked])) { if (!(nFlags & MK_SHIFT)) unmark_all(); if (on_object != -1) { if (Objects[on_object].flags[Object::Object_Flags::Marked]) unmark_object(on_object); else mark_object(on_object); } } } if (query_valid_object()) original_pos = Objects[cur_object_index].pos; moved = 0; if (Selection_lock) { if (Editing_mode == 1) drag_objects(); else if (Editing_mode == 2) drag_rotate_objects(); Update_window = 1; } if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) { Assert(Briefing_dialog); Briefing_dialog->icon_select(Objects[cur_object_index].instance); } else { if (Briefing_dialog) Briefing_dialog->icon_select(-1); } CView::OnLButtonDown(nFlags, point); } void CFREDView::OnMouseMove(UINT nFlags, CPoint point) { // RT point mouse_dx = point.x - last_mouse_x; mouse_dy = point.y - last_mouse_y; last_mouse_x = marking_box.x2 = point.x; last_mouse_y = marking_box.y2 = point.y; Cursor_over = select_object(point.x, point.y); // Orbit camera: middle button drag if (m_orbit_dragging && (nFlags & MK_MBUTTON)) { handle_orbit_drag(point, nFlags); CView::OnMouseMove(nFlags, point); return; } // Orbit camera: right button drag if (m_rbutton_down && (nFlags & MK_RBUTTON) && viewpoint == 0 && Control_mode == 0) { if (!m_rbutton_moved) { if (abs(point.x - m_rbutton_down_point.x) > 2 || abs(point.y - m_rbutton_down_point.y) > 2) m_rbutton_moved = true; } if (m_rbutton_moved) { handle_orbit_drag(point, nFlags); CView::OnMouseMove(nFlags, point); return; } } if (!(nFlags & MK_LBUTTON)) button_down = 0; // The following will cancel a drag operation if another program running in memory // happens to jump in and take over (such as new email has arrived popup boxes). if (button_down && GetCapture() != this) cancel_drag(); if (!button_down && !m_orbit_dragging && !m_rbutton_down && GetCapture() == this) ReleaseCapture(); if (button_down) { if (abs(marking_box.x1 - marking_box.x2) > 1 || abs(marking_box.y1 - marking_box.y2) > 1) moved = 1; if (moved) { if (on_object != -1 || Selection_lock) { if (Editing_mode == 1) drag_objects(); else if (Editing_mode == 2) drag_rotate_objects(); } else if (!Bg_bitmap_dialog) box_marking = 1; if (mouse_dx || mouse_dy) Update_window = 1; } } CView::OnMouseMove(nFlags, point); } void CFREDView::OnLButtonUp(UINT nFlags, CPoint point) { marking_box.x2 = point.x; marking_box.y2 = point.y; if (button_down && GetCapture() != this) cancel_drag(); if (!m_orbit_dragging && !m_rbutton_down && GetCapture() == this) ReleaseCapture(); if (button_down) { if ((abs(marking_box.x1 - marking_box.x2) > 1) || (abs(marking_box.y1 - marking_box.y2) > 1)) moved = 1; if (moved) { if ((on_object != -1) || Selection_lock) { if (Editing_mode == 1) drag_objects(); else if ((Editing_mode == 2) || (Editing_mode == 3)) drag_rotate_objects(); set_modified(); FREDDoc_ptr->autosave("object move"); } else box_marking = 1; } if (Bg_bitmap_dialog) { box_marking = 0; } else { if (box_marking) { select_objects(); box_marking = 0; } else if ((!moved && on_object != -1) && !Selection_lock && !(nFlags & MK_SHIFT)) { unmark_all(); mark_object(on_object); } } button_down = 0; Update_window = 1; if (Dup_drag == DUP_DRAG_OF_WING) { char msg[256]; int ship; object *objp; sprintf(msg, "Add cloned ships to wing %s?", Wings[Duped_wing].name); if (MessageBox(msg, "Query", MB_YESNO) == IDYES) { objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->flags[Object::Object_Flags::Marked]) { if (Wings[Duped_wing].wave_count >= MAX_SHIPS_PER_WING) { MessageBox("Max ships per wing limit reached"); break; } // Can't do player starts, since only player 1 is currently allowed to be in a wing Assert(objp->type == OBJ_SHIP); ship = objp->instance; Assert(Ships[ship].wingnum == -1); char new_name[NAME_LENGTH]; wing_bash_ship_name(new_name, Wings[Duped_wing].name, Wings[Duped_wing].wave_count + 1); rename_ship(ship, new_name); // bash it again for the display name wing_bash_ship_name(&Ships[ship], &Wings[Duped_wing], Wings[Duped_wing].wave_count + 1, true); Wings[Duped_wing].ship_index[Wings[Duped_wing].wave_count] = ship; Ships[ship].wingnum = Duped_wing; wing_objects[Duped_wing][Wings[Duped_wing].wave_count] = OBJ_INDEX(objp); Wings[Duped_wing].wave_count++; } objp = GET_NEXT(objp); } } } } if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) { Assert(Briefing_dialog); Briefing_dialog->icon_select(Objects[cur_object_index].instance); } else { if (Briefing_dialog) Briefing_dialog->icon_select(-1); } CView::OnLButtonUp(nFlags, point); } // ---------- Orbit camera mouse handlers ---------- void CFREDView::handle_orbit_drag(CPoint point, UINT nFlags) { int dx = point.x - m_orbit_last_mouse.x; int dy = point.y - m_orbit_last_mouse.y; m_orbit_last_mouse = point; if (nFlags & MK_SHIFT) orbit_camera_pan(dx, dy); else orbit_camera_rotate(dx, dy); Update_window = 1; } void CFREDView::OnMButtonDown(UINT nFlags, CPoint point) { if (viewpoint != 0 || Control_mode != 0) return; vec3d pivot = orbit_camera_get_pivot(); auto grid_orient = The_grid ? &The_grid->gmatrix : nullptr; orbit_camera_init_from_current_view(&pivot, grid_orient); m_orbit_dragging = true; m_orbit_last_mouse = point; SetCapture(); } void CFREDView::OnMButtonUp(UINT nFlags, CPoint point) { if (m_orbit_dragging) { m_orbit_dragging = false; if (GetCapture() == this && !m_rbutton_down) ReleaseCapture(); } } void CFREDView::OnRButtonDown(UINT nFlags, CPoint point) { m_rbutton_down = true; m_rbutton_moved = false; m_rbutton_down_point = point; m_orbit_last_mouse = point; if (viewpoint == 0 && Control_mode == 0) { vec3d pivot = orbit_camera_get_pivot(); auto grid_orient = The_grid ? &The_grid->gmatrix : nullptr; orbit_camera_init_from_current_view(&pivot, grid_orient); SetCapture(); } } void CFREDView::OnRButtonUp(UINT nFlags, CPoint point) { bool was_dragging = m_rbutton_moved; m_rbutton_down = false; m_rbutton_moved = false; if (GetCapture() == this && !m_orbit_dragging) ReleaseCapture(); if (!was_dragging) { // No drag occurred — show context menu as normal CPoint screen_point = point; ClientToScreen(&screen_point); OnContextMenu(this, screen_point); } } BOOL CFREDView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { if (viewpoint != 0 || Control_mode != 0) return CView::OnMouseWheel(nFlags, zDelta, pt); if (!Orbit_active) { vec3d pivot = orbit_camera_get_pivot(); auto grid_orient = The_grid ? &The_grid->gmatrix : nullptr; orbit_camera_init_from_current_view(&pivot, grid_orient); } orbit_camera_zoom(zDelta / -200.0f); Update_window = 1; return TRUE; } // ---------- End orbit camera mouse handlers ---------- // This function never gets called because nothing causes // the WM_GOODBYE event to occur. // False! When you close the Ship Dialog, this function is called! --MK, 8/30/96 LRESULT CFREDView::OnGoodbye(WPARAM wParam, LPARAM lParam) { Ship_editor_dialog.DestroyWindow(); Wing_editor_dialog.DestroyWindow(); return 0L; } void CFREDView::OnEditorsShips() { Assert(Ship_editor_dialog.GetSafeHwnd()); if (!theApp.init_window(&Ship_wnd_data, &Ship_editor_dialog, 0)) return; Ship_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Ship_editor_dialog.ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsProps() { Assert(Prop_editor_dialog.GetSafeHwnd()); if (!theApp.init_window(&Prop_wnd_data, &Prop_editor_dialog, 0)) return; Prop_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Prop_editor_dialog.ShowWindow(SW_RESTORE); } void CFREDView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT lParam) { uint lKeyData; lKeyData = lParam & 255; // key data if (lParam & 256) lKeyData += 0x80; key_mark(lKeyData, 1, 0); CView::OnKeyDown(nChar, nRepCnt, lParam); } void CFREDView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT lParam) { uint lKeyData; lKeyData = lParam & 255; // key data if (lParam & 256) lKeyData += 0x80; key_mark(lKeyData, 0, 0); CView::OnKeyUp(nChar, nRepCnt, lParam); } void CFREDView::OnSetFocus(CWnd* pOldWnd) { static int flag = 0; if (flag) return; flag = 1; nprintf(("Fred routing", "OnSetFocus() called\n")); if (Update_ship) { Ship_editor_dialog.initialize_data(1); Update_ship = 0; } if (Update_wing) { Wing_editor_dialog.initialize_data(1); Update_wing = 0; } if (Update_prop) { Prop_editor_dialog.initialize_data(1); Update_prop = 0; } if (update_dialog_boxes()) { nprintf(("Fred routing", "OnSetFocus() returned (error occured)\n")); flag = 0; Ship_editor_dialog.bypass_errors = 0; Wing_editor_dialog.bypass_errors = 0; return; // abort } if (Local_modified) { FREDDoc_ptr->autosave("Editing"); Local_modified = 0; } Fred_active = true; CView::OnSetFocus(pOldWnd); nprintf(("Fred routing", "Main window focus accepted\n")); key_got_focus(); Cursor_over = -1; if (GetActiveWindow() != Fred_main_wnd) { // If you get this assert make sure code.lib is compiling under the flags FRED and FRED_OGL Assert(Fred_main_wnd); Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); nprintf(("Fred routing", "OnSetFocus() had to put main window back on top\n")); } flag = 0; } void CFREDView::OnKillFocus(CWnd* pNewWnd) { nprintf(("Fred routing", "OnKillFocus() called\n")); Fred_active = false; Local_modified = 0; CView::OnKillFocus(pNewWnd); key_lost_focus(); Cursor_over = -1; } void CFREDView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if (cy > 0) { gr_screen_resize(cx, cy); RedrawWindow(); } } void do_trackball_stuff(int nFlags, CPoint point) { int btn = 0; if (nFlags & MK_LBUTTON){ btn |= 1; } if (nFlags & MK_RBUTTON){ btn |= 2; } move_mouse(btn, point.x, point.y); } // If add_flag != 0, then add found objects to current wing, else create new wing. void select_objects() { int x, y, valid, icon_mode = 0; vertex v; object *ptr; if (marking_box.x1 > marking_box.x2) { x = marking_box.x1; marking_box.x1 = marking_box.x2; marking_box.x2 = x; } if (marking_box.y1 > marking_box.y2) { y = marking_box.y1; marking_box.y1 = marking_box.y2; marking_box.y2 = y; } ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { valid = 1; if (ptr->flags.any_of(Object::Object_Flags::Hidden, Object::Object_Flags::Locked_from_editing)) valid = 0; Assert(ptr->type != OBJ_NONE); switch (ptr->type) { case OBJ_WAYPOINT: if (!Show_waypoints) valid = 0; break; case OBJ_START: if (!Show_starts || !Show_ships) valid = 0; break; case OBJ_SHIP: if (!Show_ships) valid = 0; if (!Show_iff[Ships[ptr->instance].team]) valid = 0; break; } g3_rotate_vertex(&v, &ptr->pos); if (!(v.codes & CC_BEHIND) && valid) if (!(g3_project_vertex(&v) & PF_OVERFLOW)) { x = (int) v.screen.xyw.x; y = (int) v.screen.xyw.y; if (x >= marking_box.x1 && x <= marking_box.x2 && y >= marking_box.y1 && y <= marking_box.y2) { if (ptr->flags[Object::Object_Flags::Marked]) unmark_object(OBJ_INDEX(ptr)); else mark_object(OBJ_INDEX(ptr)); if (ptr->type == OBJ_POINT) icon_mode = 1; } } ptr = GET_NEXT(ptr); } if (icon_mode) { ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if ((ptr->flags[Object::Object_Flags::Marked]) && (ptr->type != OBJ_POINT)) unmark_object(OBJ_INDEX(ptr)); ptr = GET_NEXT(ptr); } } Update_ship = Update_wing = Update_prop = 1; } LRESULT CFREDView::OnMenuPopupShips(WPARAM wParam, LPARAM lParam) { CMenu menu; CPoint point; point = * ((CPoint*) lParam); ClientToScreen(&point); menu.LoadMenu(IDR_MENU_SHIP_POPUP); menu.GetSubMenu(0)->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); return 0L; } LRESULT CFREDView::OnMenuPopupEdit(WPARAM wParam, LPARAM lParam) { CMenu menu; CPoint point; point = * ((CPoint*) lParam); ClientToScreen(&point); menu.LoadMenu(IDR_MENU_EDIT_POPUP); menu.GetSubMenu(0)->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); return 0L; } int g_Ships_as_icons = 0; void CFREDView::OnMiscstuffShowshipsasicons() { Update_window = 1; if (g_Ships_as_icons == 0) g_Ships_as_icons = 1; else g_Ships_as_icons = 0; } // right mouse button popup menu stuff void CFREDView::OnContextMenu(CWnd* /*pWnd*/, CPoint point) { // make sure window is active // GetParentFrame()->ActivateFrame(); CMenu menu; int objnum; CPoint local = point; if (button_down) { cancel_drag(); return; } ScreenToClient(&local); objnum = select_object(local.x, local.y); if (objnum != -1) { set_cur_object_index(objnum); if (menu.LoadMenu(IDR_MENU_SHIP_POPUP)) { int id = ID_EDITORS_SHIPS; CMenu* pPopup = menu.GetSubMenu(0); Assert(pPopup != nullptr); if (Marked > 1) pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, ID_EDITORS_SHIPS, "Edit Marked Ships"); else { CString str; if ((Objects[objnum].type == OBJ_START) || (Objects[objnum].type == OBJ_SHIP)) { str.Format("Edit %s", Ships[Objects[objnum].instance].ship_name); } else if (Objects[objnum].type == OBJ_PROP) { id = ID_EDITORS_PROPS; str.Format("Edit %s", prop_id_lookup(Objects[objnum].instance)->prop_name); } else if (Objects[objnum].type == OBJ_JUMP_NODE) { auto jnp = jumpnode_get_by_objnum(objnum); Assert(jnp != nullptr); id = ID_EDITORS_JUMPNODE; str.Format("Edit %s", jnp->GetName()); } else if (Objects[objnum].type == OBJ_WAYPOINT) { char text[NAME_LENGTH]; waypoint_stuff_name(text, Objects[objnum].instance); id = ID_EDITORS_WAYPOINT; str.Format("Edit %s", text); } else if (Objects[objnum].type == OBJ_POINT) { return; } else { Int3(); str = _T("Unknown"); } pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, id, str); } pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()); // use main window for cmds } } else { if (menu.LoadMenu(IDR_MENU_EDIT_POPUP)) { size_t i; CMenu* pPopup = menu.GetSubMenu(0); CMenu shipPopup, player_submenu; CMenu *species_submenu = new CMenu[Species_info.size()]; Assert(pPopup != nullptr); // create a popup menu based on the ship models read in ship.cpp. // note: the offsets from SHIP_TYPES must correspond to the indexes in the ship type dropdown shipPopup.CreatePopupMenu(); shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_waypoint, "Waypoint"); shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_jump_node, "Jump Node"); for (i=0; iflags[Ship::Info_Flags::No_fred]) continue; // because the dropdown skips "no_fred", we need to skip it here too species_submenu[it->species].AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + i, it->name); i++; } pPopup->AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED, (UINT) shipPopup.m_hMenu, "New Object Type"); CWnd::DrawMenuBar(); // AppendMenu documentation says to do this. pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()); } } } void CFREDView::OnEditPopupShowShipIcons() { Show_ship_info = !Show_ship_info; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateEditPopupShowShipIcons(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_ship_info); } void CFREDView::OnEditPopupShowShipModels() { Show_ship_models = !Show_ship_models; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateEditPopupShowShipModels(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_ship_models); } void CFREDView::OnEditPopupShowCompass() { Show_compass = !Show_compass; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateEditPopupShowCompass(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_compass); } // View implementation file CFREDView *CFREDView::GetView() { CFrameWnd *pFrame = (CFrameWnd *) (AfxGetApp()->m_pMainWnd); CView *pView = pFrame->GetActiveView(); if (!pView) return NULL; // Fail if view is of wrong kind // (this could occur with splitter windows, or additional // views on a single document if (! pView->IsKindOf(RUNTIME_CLASS(CFREDView))) return NULL; return (CFREDView *) pView; } // following code added by MWA 09/04/96 // Implements messages for popup menu built on the fly. // not sure how stable the code is, but appears to work for now. // id's for the menu items are simply the model numbers for // the ships. Shouldn't conflict with any other ID_* thingys. BOOL CFREDView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { if (!pHandlerInfo) { if ((nID >= SHIP_TYPES) && (nID < SHIP_TYPES + ship_type_combo_box_size + 2)) { // the 2 are waypoint and jump node int idx = static_cast(nID - SHIP_TYPES); if (nCode == CN_COMMAND) { cur_ship_type_combo_index = idx; m_new_ship_type_combo_box.SetCurSel(cur_ship_type_combo_index); // now that we've updated the combo box, try to actually create something // see also CFREDView::OnLButtonDown int waypoint_instance = cur_waypoint ? Objects[cur_waypoint->get_objnum()].instance : -1; Selection_lock = 0; on_object = create_object_on_grid(waypoint_instance); } else if (nCode == CN_UPDATE_COMMAND_UI) { // Update UI element state ((CCmdUI*) pExtra)->SetCheck(cur_ship_type_combo_index == idx); ((CCmdUI*) pExtra)->Enable(TRUE); } return TRUE; } } return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } void CFREDView::OnMiscStatistics() { char buf[2048]; sprintf(buf, "Number of Objects: %d\n" "Number of Ships: %d\n" "Number of Wings: %d\n", Num_objects, ship_get_num_ships(), Num_wings); MessageBox(buf, "FRED Statistics"); } void CFREDView::OnUpdateChangeViewpointExternal(CCmdUI* pCmdUI) { pCmdUI->SetCheck(!viewpoint); } void CFREDView::OnChangeViewpointExternal() { viewpoint = 0; Update_window = 1; } void CFREDView::OnUpdateChangeViewpointFollow(CCmdUI* pCmdUI) { pCmdUI->SetCheck(viewpoint == 1); } void CFREDView::OnChangeViewpointFollow() { viewpoint = 1; view_obj = cur_object_index; Update_window = 1; } void CFREDView::OnOutlineLod(int lod) { Outline_lod = lod; Update_window = 1; } void CFREDView::OnUpdateOutlineLod(int lod, CCmdUI* pCmdUI) { pCmdUI->SetCheck(Outline_lod == lod); } void CFREDView::OnOutlineLod0() { OnOutlineLod(0); } void CFREDView::OnOutlineLod1() { OnOutlineLod(1); } void CFREDView::OnOutlineLod2() { OnOutlineLod(2); } void CFREDView::OnOutlineLod3() { OnOutlineLod(3); } void CFREDView::OnOutlineLod4() { OnOutlineLod(4); } void CFREDView::OnUpdateOutlineLod0(CCmdUI* pCmdUI) { OnUpdateOutlineLod(0, pCmdUI); } void CFREDView::OnUpdateOutlineLod1(CCmdUI* pCmdUI) { OnUpdateOutlineLod(1, pCmdUI); } void CFREDView::OnUpdateOutlineLod2(CCmdUI* pCmdUI) { OnUpdateOutlineLod(2, pCmdUI); } void CFREDView::OnUpdateOutlineLod3(CCmdUI* pCmdUI) { OnUpdateOutlineLod(3, pCmdUI); } void CFREDView::OnUpdateOutlineLod4(CCmdUI* pCmdUI) { OnUpdateOutlineLod(4, pCmdUI); } void CFREDView::OnLabelFontScale(float scale) { Fred_label_font_scale = scale; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateLabelFontScale(float scale, CCmdUI* pCmdUI) { // tolerant compare, since the value is stored as a float derived from an int percentage pCmdUI->SetCheck(fl_equal(Fred_label_font_scale, scale, 0.001f)); } void CFREDView::OnLabelFontScale50() { OnLabelFontScale(0.5f); } void CFREDView::OnLabelFontScale75() { OnLabelFontScale(0.75f); } void CFREDView::OnLabelFontScale100() { OnLabelFontScale(1.0f); } void CFREDView::OnLabelFontScale125() { OnLabelFontScale(1.25f); } void CFREDView::OnLabelFontScale150() { OnLabelFontScale(1.5f); } void CFREDView::OnLabelFontScale200() { OnLabelFontScale(2.0f); } void CFREDView::OnLabelFontScale250() { OnLabelFontScale(2.5f); } void CFREDView::OnLabelFontScale300() { OnLabelFontScale(3.0f); } void CFREDView::OnLabelFontScale350() { OnLabelFontScale(3.5f); } void CFREDView::OnLabelFontScale400() { OnLabelFontScale(4.0f); } void CFREDView::OnUpdateLabelFontScale50(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(0.5f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale75(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(0.75f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale100(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(1.0f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale125(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(1.25f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale150(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(1.5f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale200(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(2.0f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale250(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(2.5f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale300(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(3.0f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale350(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(3.5f, pCmdUI); } void CFREDView::OnUpdateLabelFontScale400(CCmdUI* pCmdUI) { OnUpdateLabelFontScale(4.0f, pCmdUI); } void CFREDView::OnEditorsGoals() { CMissionGoalsDlg dlg; dlg.DoModal(); } void CFREDView::OnEditorsCutscenes() { CMissionCutscenesDlg dlg; dlg.DoModal(); } void CFREDView::OnSpeed1() { physics_speed = 1; set_physics_controls(); } void CFREDView::OnSpeed2() { physics_speed = 2; set_physics_controls(); } void CFREDView::OnSpeed3() { physics_speed = 3; set_physics_controls(); } void CFREDView::OnSpeed5() { physics_speed = 5; set_physics_controls(); } void CFREDView::OnSpeed8() { physics_speed = 8; set_physics_controls(); } void CFREDView::OnSpeed10() { physics_speed = 10; set_physics_controls(); } void CFREDView::OnSpeed50() { physics_speed = 50; set_physics_controls(); } void CFREDView::OnSpeed100() { physics_speed = 100; set_physics_controls(); } void CFREDView::OnSpeed500() { physics_speed = 500; set_physics_controls(); } void CFREDView::OnSpeed1000() { physics_speed = 1000; set_physics_controls(); } void CFREDView::OnRot1() { physics_rot = 2; set_physics_controls(); } void CFREDView::OnRot2() { physics_rot = 10; set_physics_controls(); } void CFREDView::OnRot3() { physics_rot = 25; set_physics_controls(); } void CFREDView::OnRot4() { physics_rot = 50; set_physics_controls(); } void CFREDView::OnRot5() { physics_rot = 100; set_physics_controls(); } void CFREDView::OnUpdateSpeed1(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 1); } void CFREDView::OnUpdateSpeed2(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 2); } void CFREDView::OnUpdateSpeed3(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 3); } void CFREDView::OnUpdateSpeed5(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 5); } void CFREDView::OnUpdateSpeed8(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 8); } void CFREDView::OnUpdateSpeed10(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 10); } void CFREDView::OnUpdateSpeed50(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 50); } void CFREDView::OnUpdateSpeed100(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 100); } void CFREDView::OnUpdateSpeed500(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 500); } void CFREDView::OnUpdateSpeed1000(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_speed == 1000); } void CFREDView::OnUpdateRot1(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_rot == 2); } void CFREDView::OnUpdateRot2(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_rot == 10); } void CFREDView::OnUpdateRot3(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_rot == 25); } void CFREDView::OnUpdateRot4(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_rot == 50); } void CFREDView::OnUpdateRot5(CCmdUI* pCmdUI) { pCmdUI->SetCheck(physics_rot == 100); } void CFREDView::OnControlModeCamera() { Control_mode = 0; } void CFREDView::OnUpdateControlModeCamera(CCmdUI* pCmdUI) { pCmdUI->SetCheck(!Control_mode); } void CFREDView::OnControlModeShip() { Control_mode = 1; } void CFREDView::OnUpdateControlModeShip(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Control_mode == 1); } void CFREDView::OnShowGridPositions() { Show_grid_positions = !Show_grid_positions; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowGridPositions(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_grid_positions); } void CFREDView::OnShowCoordinates() { Show_coordinates = !Show_coordinates; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowCoordinates(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_coordinates); } void CFREDView::OnSelect() { Editing_mode = 0; } void CFREDView::OnUpdateSelect(CCmdUI* pCmdUI) { pCmdUI->SetCheck(!Editing_mode); } void CFREDView::OnSelectAndMove() { Editing_mode = 1; } void CFREDView::OnUpdateSelectAndMove(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Editing_mode == 1); } void CFREDView::OnSelectAndRotate() { Editing_mode = 2; } void CFREDView::OnUpdateSelectAndRotate(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Editing_mode == 2); } void CFREDView::OnConstrainX() { vm_vec_make(&Constraint, 1.0f, 0.0f, 0.0f); vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 1.0f); Single_axis_constraint = 1; } void CFREDView::OnUpdateConstrainX(CCmdUI* pCmdUI) { pCmdUI->SetRadio(Constraint.xyz.x && !Constraint.xyz.y && !Constraint.xyz.z); } void CFREDView::OnConstrainY() { vm_vec_make(&Constraint, 0.0f, 1.0f, 0.0f); vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 1.0f); Single_axis_constraint = 1; } void CFREDView::OnUpdateConstrainY(CCmdUI* pCmdUI) { pCmdUI->SetRadio(!Constraint.xyz.x && Constraint.xyz.y && !Constraint.xyz.z); } void CFREDView::OnConstrainZ() { vm_vec_make(&Constraint, 0.0f, 0.0f, 1.0f); vm_vec_make(&Anticonstraint, 1.0f, 1.0f, 0.0f); Single_axis_constraint = 1; } void CFREDView::OnUpdateConstrainZ(CCmdUI* pCmdUI) { pCmdUI->SetRadio(!Constraint.xyz.x && !Constraint.xyz.y && Constraint.xyz.z); } void CFREDView::OnConstrainXz() { vm_vec_make(&Constraint, 1.0f, 0.0f, 1.0f); vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 0.0f); Single_axis_constraint = 0; } void CFREDView::OnUpdateConstrainXz(CCmdUI* pCmdUI) { pCmdUI->SetRadio(Constraint.xyz.x && !Constraint.xyz.y && Constraint.xyz.z); } void CFREDView::OnConstrainXy() { vm_vec_make(&Constraint, 1.0f, 1.0f, 0.0f); vm_vec_make(&Anticonstraint, 0.0f, 0.0f, 1.0f); Single_axis_constraint = 0; } void CFREDView::OnUpdateConstrainXy(CCmdUI* pCmdUI) { pCmdUI->SetRadio(Constraint.xyz.x && Constraint.xyz.y && !Constraint.xyz.z); } void CFREDView::OnConstrainYz() { vm_vec_make(&Constraint, 0.0f, 1.0f, 1.0f); vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 0.0f); Single_axis_constraint = 0; } void CFREDView::OnUpdateConstrainYz(CCmdUI* pCmdUI) { pCmdUI->SetRadio(!Constraint.xyz.x && Constraint.xyz.y && Constraint.xyz.z); } void CFREDView::OnSelectionLock() { Selection_lock = !Selection_lock; } void CFREDView::OnUpdateSelectionLock(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Selection_lock); } void CFREDView::OnLButtonDblClk(UINT nFlags, CPoint point) { CView::OnLButtonDblClk(nFlags, point); if (Cursor_over != -1) { switch (Objects[Cursor_over].type) { case OBJ_SHIP: case OBJ_START: OnEditorsShips(); break; case OBJ_PROP: OnEditorsProps(); break; case OBJ_WAYPOINT: OnEditorsWaypoint(); break; case OBJ_JUMP_NODE: OnEditorsJumpnode(); break; } } else if (Briefing_dialog) Fixed_briefing_size = !Fixed_briefing_size; } void CFREDView::OnDoubleFineGridlines() { double_fine_gridlines = !double_fine_gridlines; maybe_create_new_grid(The_grid, &eye_pos, &eye_orient, 1); theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateDoubleFineGridlines(CCmdUI* pCmdUI) { pCmdUI->SetCheck(double_fine_gridlines); } void CFREDView::OnShowDistances() { Show_distances = !Show_distances; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowDistances(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_distances); } void CFREDView::OnUniversalHeading() { Universal_heading = !Universal_heading; } void CFREDView::OnUpdateUniversalHeading(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Universal_heading); } void CFREDView::OnFlyingControls() { Flying_controls_mode = !Flying_controls_mode; } void CFREDView::OnUpdateFlyingControls(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Flying_controls_mode); } void CFREDView::OnRotateLocally() { Group_rotate = !Group_rotate; } void CFREDView::OnUpdateRotateLocally(CCmdUI* pCmdUI) { pCmdUI->SetCheck(!Group_rotate); } void CFREDView::OnSelectList() { ship_select dlg; dlg.DoModal(); } // position camera to view all objects on the screen at once. Doesn't change orientation. void view_universe(int just_marked) { float dist, radius; vec3d center; vertex v; object *ptr; if (!get_object_bounds(just_marked != 0, ¢er, &radius)) return; dist = std::max(radius, fl_sqrt(20.0f)) + 1.0f; vm_vec_scale_add(&view_pos, ¢er, &view_orient.vec.fvec, -dist); g3_set_view_matrix(&view_pos, &view_orient, 0.5f); ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (!just_marked || (ptr->flags[Object::Object_Flags::Marked])) { g3_rotate_vertex(&v, &ptr->pos); Assert(!(v.codes & CC_BEHIND)); if (g3_project_vertex(&v) & PF_OVERFLOW) Int3(); while (v.codes & CC_OFF) { // is point off screen? dist += 5.0f; // zoom out a little and check again. vm_vec_scale_add(&view_pos, ¢er, &view_orient.vec.fvec, -dist); g3_set_view_matrix(&view_pos, &view_orient, 0.5f); g3_rotate_vertex(&v, &ptr->pos); if (g3_project_vertex(&v) & PF_OVERFLOW) Int3(); } } ptr = GET_NEXT(ptr); } dist *= 1.1f; vm_vec_scale_add(&view_pos, ¢er, &view_orient.vec.fvec, -dist); g3_set_view_matrix(&view_pos, &view_orient, 0.5f); Update_window = 1; } void CFREDView::cycle_constraint() { if (Single_axis_constraint) { if (Constraint.xyz.x) OnConstrainY(); else if (Constraint.xyz.y) OnConstrainZ(); else if (Constraint.xyz.z) OnConstrainXz(); } else { if (!Constraint.xyz.x) OnConstrainXy(); else if (!Constraint.xyz.y) OnConstrainYz(); else if (!Constraint.xyz.z) OnConstrainX(); } } void CFREDView::OnZoomExtents() { view_universe(); } void CFREDView::OnZoomSelected() { if (query_valid_object()) { if (Marked > 1) view_universe(1); else vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.vec.fvec, Objects[cur_object_index].radius * -3.0f); } Update_window = 1; } void CFREDView::OnUpdateZoomSelected(CCmdUI* pCmdUI) { pCmdUI->Enable(query_valid_object()); } void CFREDView::OnFormWing() { object *ptr = GET_FIRST(&obj_used_list); bool found = false; while (ptr != END_OF_LIST(&obj_used_list)) { if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags[Object::Object_Flags::Marked])) { if(Ships[ptr->instance].flags[Ship::Ship_Flags::Reinforcement]) { found = true; break; } } ptr = GET_NEXT(ptr); } if(found) { 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); if(ok == IDOK) { ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags[Object::Object_Flags::Marked])) { set_reinforcement(Ships[ptr->instance].ship_name, 0); } ptr = GET_NEXT(ptr); } } else { return; } } if (!create_wing()) FREDDoc_ptr->autosave("form wing"); } void CFREDView::OnUpdateFormWing(CCmdUI* pCmdUI) { int count = 0; object *ptr; if (query_valid_object()) { ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->flags[Object::Object_Flags::Marked]) { if (ptr->type == OBJ_SHIP) { int ship_type = ship_query_general_type(ptr->instance); if(ship_type > -1 && (Ship_types[ship_type].flags[Ship::Type_Info_Flags::AI_can_form_wing])) { count++; } } if (ptr->type == OBJ_START) count++; } ptr = GET_NEXT(ptr); } } pCmdUI->Enable(count > 0); } int query_single_wing_marked() { int i, obj; if (!query_valid_object()) return 0; if (cur_wing == -1) return 0; i = Wings[cur_wing].wave_count; if (Marked != i) // does marked object count match number of ships in wing? return 0; while (i--) { obj = wing_objects[cur_wing][i]; if ((Objects[obj].type != OBJ_SHIP) && (Objects[obj].type != OBJ_START)) Error(LOCATION, "Invalid objects detected in wing \"%s\"", Wings[cur_wing].name); // if (Ships[Objects[obj].instance].wingnum != cur_wing) // return 0; Assert(Ships[Objects[obj].instance].wingnum == cur_wing); if (!(Objects[obj].flags[Object::Object_Flags::Marked])) // ensure all ships in wing.are marked return 0; } return 1; } void CFREDView::OnDisbandWing() { if (query_single_wing_marked()) { disband_wing(cur_wing); FREDDoc_ptr->autosave("wing disband"); } else MessageBox("One and only one wing must be selected for this operation"); } void CFREDView::OnUpdateDisbandWing(CCmdUI* pCmdUI) { pCmdUI->Enable(query_single_wing_marked()); } void CFREDView::OnShowHorizon() { Show_horizon = !Show_horizon; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowHorizon(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_horizon); } void CFREDView::OnEditorsWing() { Assert(Wing_editor_dialog.GetSafeHwnd()); if (!theApp.init_window(&Wing_wnd_data, &Wing_editor_dialog, 0)) return; Wing_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Wing_editor_dialog.ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsPlayer() { player_start_editor dlg; dlg.DoModal(); } void CFREDView::OnEditorsOrient() { orient_editor dlg; dlg.DoModal(); } void CFREDView::OnEditorsEvents() { if (Message_editor_dlg) { MessageBox("You must close the message editor before opening the event editor"); return; } if (!Event_editor_dlg) { Event_editor_dlg = new event_editor; Event_editor_dlg->Create(event_editor::IDD); } Event_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Event_editor_dlg->ShowWindow(SW_RESTORE); } void CFREDView::OnUpdateEditorsOrient(CCmdUI* pCmdUI) { pCmdUI->Enable(query_valid_object()); } void CFREDView::OnEditorsMessage() { if (Event_editor_dlg) { MessageBox("You must close the event editor before opening the message editor"); return; } if (!Message_editor_dlg) { Message_editor_dlg = new CMessageEditorDlg; Message_editor_dlg->Create(CMessageEditorDlg::IDD); } Message_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Message_editor_dlg->ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsStarfield() { starfield_editor dlg; dlg.DoModal(); } void CFREDView::place_background_bitmap(vec3d v) { } void CFREDView::OnEditorsBgBitmaps() { if (!Bg_bitmap_dialog) { Bg_bitmap_dialog = new bg_bitmap_dlg; Bg_bitmap_dialog->create(); } Bg_bitmap_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Bg_bitmap_dialog->ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsVolumetrics() { volumetrics_dlg dlg; dlg.DoModal(); } void CFREDView::OnEditorsReinforcement() { reinforcement_editor_dlg dlg; dlg.DoModal(); } void CFREDView::OnErrorChecker() { int z; z = global_error_check(); if (!z) MessageBox("No errors were detected in this mission", "Woohoo!"); for (z=0; z anchors_checked; g_err = multi = 0; if ( The_mission.game_type & MISSION_TYPE_MULTI ) multi = 1; // cycle though all the objects and verify every possible aspect of them obj_count = t = 0; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { names[obj_count] = NULL; flags[obj_count] = 0; i = ptr->instance; if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) { if (i < 0 || i >= MAX_SHIPS){ return internal_error("An object has an illegal ship index"); } z = Ships[i].ship_info_index; if ((z < 0) || (z >= ship_info_size())){ return internal_error("A ship has an illegal class"); } if (ptr->type == OBJ_START) { t++; if (!(Ship_info[z].flags[Ship::Info_Flags::Player_ship])) { ptr->type = OBJ_SHIP; Player_starts--; t--; ensure_valid_player_start_shipnum(); if (error("Invalid ship type for a player. Ship has been reset to non-player ship.")){ return 1; } } for (n=count=0; n= 0){ count++; } } if (!count){ if (error("Player \"%s\" has no primary weapons. Should have at least 1", Ships[i].ship_name)){ return 1; } } for (n=count=0; n= 0){ count++; } } } if (Ships[i].objnum != OBJ_INDEX(ptr)){ return internal_error("Object/ship references are corrupt"); } names[obj_count] = Ships[i].ship_name; wing = Ships[i].wingnum; if (wing >= 0) { // ship is part of a wing, so check this if (wing < 0 || wing >= MAX_WINGS){ // completely out of range? return internal_error("A ship has an illegal wing index"); } j = Wings[wing].wave_count; if (!j){ return internal_error("A ship is in a non-existent wing"); } if (j < 0 || j > MAX_SHIPS_PER_WING){ return internal_error("Invalid number of ships in wing \"%s\"", Wings[z].name); } while (j--){ if (wing_objects[wing][j] == OBJ_INDEX(ptr)){ // look for object in wing's table break; } } if (j < 0){ return internal_error("Ship/wing references are corrupt"); } // wing squad logo check - Goober5000 if (strlen(Wings[wing].wing_squad_filename) > 0) //-V805 { if (The_mission.game_type & MISSION_TYPE_MULTI) { if (error("Wing squad logos are not displayed in multiplayer games.")) { return 1; } } else { if (ptr->type == OBJ_START) { 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.")) { return 1; } } } } } if ( (Ships[i].flags[Ship::Ship_Flags::Kill_before_mission]) && (Ships[i].hotkey >= 0) ){ if (error("Ship flagged as \"destroy before mission start\" has a hotkey assignment")){ return 1; } } if ( (Ships[i].flags[Ship::Ship_Flags::Kill_before_mission]) && (ptr->type == OBJ_START) ){ if (error("Player start flagged as \"destroy before mission start\"")){ return 1; } } } else if (ptr->type == OBJ_WAYPOINT) { int waypoint_num; waypoint_list *wp_list = find_waypoint_list_with_instance(i, &waypoint_num); if (wp_list == NULL) { return internal_error("Object references an illegal waypoint path number"); } if (waypoint_num < 0 || (uint) waypoint_num >= wp_list->get_waypoints().size()) { return internal_error("Object references an illegal waypoint number in path"); } waypoint_stuff_name(buf, i); names[obj_count] = new char[strlen(buf) + 1]; strcpy(names[obj_count], buf); flags[obj_count] = 1; } else if (ptr->type == OBJ_POINT) { if (!Briefing_dialog){ return internal_error("Briefing icon detected when not in briefing edit mode"); } //Shouldn't be needed anymore. //If we really do need it, call me and I'll write a is_valid function for jumpnodes -WMC } else if (ptr->type == OBJ_JUMP_NODE || ptr->type == OBJ_PROP) { //nothing needs to be done here, we just need to make sure the else doesn't occur } else { return internal_error("An unknown object type (%d) was detected", ptr->type); } for (i=0; i= 0) { // is ship being used? count++; if (!query_valid_object(Ships[i].objnum)){ return internal_error("Ship uses an unused object"); } z = Objects[Ships[i].objnum].type; if ((z != OBJ_SHIP) && (z != OBJ_START)){ return internal_error("Object should be a ship, but isn't"); } if (fred_check_sexp(Ships[i].arrival_cue, OPR_BOOL, "arrival cue of ship \"%s\"", Ships[i].ship_name)){ return -1; } if (fred_check_sexp(Ships[i].departure_cue, OPR_BOOL, "departure cue of ship \"%s\"", Ships[i].ship_name)){ return -1; } if (Ships[i].arrival_location != ArrivalLocation::AT_LOCATION) { if (!Ships[i].arrival_anchor.isValid()){ if (error("Ship \"%s\" requires a valid arrival target", Ships[i].ship_name)){ return 1; } } if (Ships[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) { check_anchor_for_hangar_bay(anchor_message, anchors_checked, Ships[i].arrival_anchor, Ships[i].ship_name, true, true); if (!anchor_message.empty() && error("%s", anchor_message.c_str())) { return 1; } } } if (Ships[i].departure_location != DepartureLocation::AT_LOCATION) { if (!Ships[i].departure_anchor.isValid()){ if (error("Ship \"%s\" requires a valid departure target", Ships[i].ship_name)){ return 1; } } if (Ships[i].departure_location == DepartureLocation::TO_DOCK_BAY) { check_anchor_for_hangar_bay(anchor_message, anchors_checked, Ships[i].departure_anchor, Ships[i].ship_name, true, false); if (!anchor_message.empty() && error("%s", anchor_message.c_str())) { return 1; } } } ai = Ships[i].ai_index; if (ai < 0 || ai >= MAX_AI_INFO){ return internal_error("AI index out of range for ship \"%s\"", Ships[i].ship_name); } if (Ai_info[ai].shipnum != i){ return internal_error("AI/ship references are corrupt"); } if ((str = error_check_initial_orders(Ai_info[ai].goals, i, -1))>0) { if (*str == '*') return internal_error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str + 1); else if (*str == '!') return 1; else if (error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str)) return 1; } for (dock_instance *dock_ptr = Objects[Ships[i].objnum].dock_list; dock_ptr != NULL; dock_ptr = dock_ptr->next) { obj = OBJ_INDEX(dock_ptr->docked_objp); if (!query_valid_object(obj)){ return internal_error("Ship \"%s\" initially docked with non-existant ship", Ships[i].ship_name); } if (Objects[obj].type != OBJ_SHIP && Objects[obj].type != OBJ_START){ return internal_error("Ship \"%s\" initially docked with non-ship object", Ships[i].ship_name); } ship = get_ship_from_obj(obj); if (!ship_docking_valid(i, ship) && !ship_docking_valid(ship, i)){ return internal_error("Docking illegal between \"%s\" and \"%s\" (initially docked)", Ships[i].ship_name, Ships[ship].ship_name); } z = get_docking_list(Ship_info[Ships[i].ship_info_index].model_num); point = dock_ptr->dockpoint_used; if (point < 0 || point >= z){ internal_error("Invalid docker point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name); } z = get_docking_list(Ship_info[Ships[ship].ship_info_index].model_num); point = dock_find_dockpoint_used_by_object(dock_ptr->docked_objp, &Objects[Ships[i].objnum]); if (point < 0 || point >= z){ internal_error("Invalid dockee point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name); } } wing = Ships[i].wingnum; bool is_in_loadout_screen = (ptr->type == OBJ_START); if (!is_in_loadout_screen && wing >= 0) { if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) { for (n = 0; n < MAX_TVT_WINGS; n++) { if (!strcmp(Wings[wing].name, TVT_wing_names[n])) { is_in_loadout_screen = true; break; } } } else { for (n = 0; n < MAX_STARTING_WINGS; n++) { if (!strcmp(Wings[wing].name, Starting_wing_names[n])) { is_in_loadout_screen = true; break; } } } } if (is_in_loadout_screen) { int illegal = 0; z = Ships[i].ship_info_index; for (n = 0; n < MAX_SHIP_PRIMARY_BANKS; n++){ if (Ships[i].weapons.primary_bank_weapons[n] >= 0 && !Ship_info[z].allowed_weapons[Ships[i].weapons.primary_bank_weapons[n]]){ illegal++; } } for (n = 0; n < MAX_SHIP_SECONDARY_BANKS; n++){ if (Ships[i].weapons.secondary_bank_weapons[n] >= 0 && !Ship_info[z].allowed_weapons[Ships[i].weapons.secondary_bank_weapons[n]]){ illegal++; } } if (illegal && error("%d illegal weapon(s) found on ship \"%s\"", illegal, Ships[i].ship_name)) { return 1; } } } } if (count != ship_get_num_ships()){ return internal_error("num_ships is incorrect"); } count = 0; for (i=0; i MAX_SHIPS_PER_WING){ return internal_error("Invalid number of ships in wing \"%s\"", Wings[i].name); } while (j--) { obj = wing_objects[i][j]; if (obj < 0 || obj >= MAX_OBJECTS){ return internal_error("Wing_objects has an illegal object index"); } if (!query_valid_object(obj)){ return internal_error("Wing_objects references an unused object"); } // Now, at this point, we can assume several things. We have a valid object because // we passed query_valid_object(), and all valid objects were already checked above, // so this object has valid information, such as the instance. if ((Objects[obj].type == OBJ_SHIP) || (Objects[obj].type == OBJ_START)) { ship = Objects[obj].instance; wing_bash_ship_name(buf, Wings[i].name, j + 1); if (stricmp(buf, Ships[ship].ship_name)){ return internal_error("Ship \"%s\" in wing should be called \"%s\"", Ships[ship].ship_name, buf); } int ship_type = ship_query_general_type(ship); if(ship_type < 0 || !(Ship_types[ship_type].flags[Ship::Type_Info_Flags::AI_can_form_wing])) { if (error("Ship \"%s\" is an illegal type to be in a wing", Ships[ship].ship_name)){ return 1; } } } else { return internal_error("Wing_objects of \"%s\" references an illegal object type", Wings[i].name); } if (Ships[ship].wingnum != i){ return internal_error("Wing/ship references are corrupt"); } if (ship != Wings[i].ship_index[j]){ return internal_error("Ship/wing references are corrupt"); } if (team < 0){ team = Ships[ship].team; } else if (team != Ships[ship].team && team < 999){ if (error("ship teams mixed within same wing (\"%s\")", Wings[i].name)){ return 1; } } } if ((Wings[i].special_ship < 0) || (Wings[i].special_ship >= Wings[i].wave_count)){ return internal_error("Special ship out of range for \"%s\"", Wings[i].name); } if (Wings[i].num_waves < 0){ return internal_error("Number of waves for \"%s\" is negative", Wings[i].name); } if (Wings[i].threshold < 0){ return internal_error("Threshold for \"%s\" is invalid", Wings[i].name); } if (Wings[i].threshold + Wings[i].wave_count > MAX_SHIPS_PER_WING) { Wings[i].threshold = MAX_SHIPS_PER_WING - Wings[i].wave_count; if(error("Threshold for wing \"%s\" is higher than allowed. Reset to %d", Wings[i].name, Wings[i].threshold)){ return 1; } } for (j=0; j0) { if (*str == '*') return internal_error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str + 1); else if (*str == '!') return 1; else if (error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str)) return 1; } } } if (count != Num_wings){ return internal_error("Num_wings is incorrect"); } for (const auto &ii: Waypoint_lists) { for (z=0; z MAX_PLAYERS){ return internal_error("Number of player starts exceeds max limit"); } if (!multi && (Player_starts > 1)){ if (error("Multiple player starts exist, but this is a single player mission")){ return 1; } } for (const auto &reinforcement: Reinforcements) { z = 0; for (ship=0; ship= 0) && !stricmp(Ships[ship].ship_name, reinforcement.name)) { z = 1; break; } } for (wing=0; wing= MAX_SHIPS) // hacked! -1 should be illegal.. return internal_error("Message originator index is out of range"); if (Ships[z].objnum == -1) return internal_error("Message originator points to nonexistant ship"); if (fred_check_sexp(Messages[i].sexp, OPR_BOOL, "Message formula from \"%s\"", Ships[Messages[i].who_from].ship_name)) return -1; }*/ if ((Player_start_shipnum < 0) || (Player_start_shipnum >= MAX_SHIPS) || (Ships[Player_start_shipnum].objnum < 0)){ return internal_error("Mission has no valid player start ship"); } i = global_error_check_player_wings(multi); if (i){ return i; } for (i=0; i<(int)Mission_events.size(); i++){ if (fred_check_sexp(Mission_events[i].formula, OPR_NULL, "mission event \"%s\"", Mission_events[i].name.c_str())){ return -1; } } for (i=0; i<(int)Mission_goals.size(); i++){ if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission goal \"%s\"", Mission_goals[i].name.c_str())){ return -1; } } for ( bs = 0; bs < Num_teams; bs++ ) { for (s=0; snum_icons; for (i=0; iicons[i].id > 0) && (sp->icons[i].id == sp->icons[j].id)){ if (error("Duplicate icon IDs %d in briefing stage %d", sp->icons[i].id, s + 1)){ return 1; } } } } } } for ( j = 0; j < Num_teams; j++ ) { for (i=0; i starting_orders { std::numeric_limits::max() }; for (i=0; i default_orders; int default_orders_idx = -1; if ( !Wings[i].wave_count ){ continue; } // determine if this wing is a starting wing of the player starting_wing = (ship_starting_wing_lookup(Wings[i].name) != -1); // first, be sure this isn't a reinforcement wing. if ( starting_wing && (Wings[i].flags[Ship::Wing_Flags::Reinforcement]) ) { if ( error("Starting Wing %s marked as reinforcement. This wing\nshould either be renamed, or unmarked as reinforcement.", Wings[i].name) ){ return 1; } } for ( j = 0; j < Wings[i].wave_count; j++ ) { std::set orders; // exclude players from the check if (Objects[Ships[Wings[i].ship_index[j]].objnum].type == OBJ_START) { continue; } orders = Ships[Wings[i].ship_index[j]].orders_accepted; if ( default_orders_idx < 0 ) { default_orders_idx = j; default_orders = orders; } else if ( default_orders != orders ) { 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[default_orders_idx]].ship_name)) { return 1; } } } /* Goober5000 - this is not necessary // make sure that these ignored orders are the same for all starting wings of the player if ( starting_wing ) { if ( starting_orders == -1 ) { starting_orders = default_orders; } else { if ( starting_orders != default_orders ) { if ( error("Player starting wing %s has orders which don't match other starting wings\n", Wings[i].name) ){ return 1; } } } } */ } //This should never ever be a problem -WMC /* if (Num_jump_nodes < 0){ return internal_error("Jump node count is illegal"); }*/ // do error checking for asteroid targets for (const auto& name : Asteroid_field.target_names) { if (ship_name_lookup(name.c_str(), 1) < 0) { if (error("Asteroid target '%s' is not a valid ship", name.c_str())) { return 1; } } } fred_check_message_personas(); return g_err; } int CFREDView::global_error_check_mixed_player_wing(int w) { int i, s, species = -1, mixed = 0; for (i=0; i 1) continue; if (Wings[i].arrival_cue == Locked_sexp_true) continue; bool contains_player_start = false; for (z=0; zMessageBox(issue_buf.c_str(), "Warning", MB_OKCANCEL | MB_ICONINFORMATION) != IDOK) return 1; } } } // Check to be sure that any player wing doesn't have > 1 wave for multiplayer if ( multi ) { if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) { for (i=0; i= 0 && Wings[TVT_wings[i]].num_waves > 1) { Wings[TVT_wings[i]].num_waves = 1; if (error("%s wing must contain only 1 wave.\nThis change has been made for you.", TVT_wing_names[i])) return 1; } } } else { for (i=0; i= 0 && Wings[Starting_wings[i]].num_waves > 1) { Wings[Starting_wings[i]].num_waves = 1; if (error("%s wing must contain only 1 wave.\nThis change has been made for you.", Starting_wing_names[i])) return 1; } } } } // check number of ships in player wing if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) { for (i=0; i= 0 && Wings[TVT_wings[i]].wave_count > 4) { if (error("%s wing has too many ships. Should only have 4 max.", TVT_wing_names[i])) return 1; } } } else { for (i=0; i= 0 && Wings[Starting_wings[i]].wave_count > 4) { if (error("%s wing has too many ships. Should only have 4 max.", Starting_wing_names[i])) return 1; } } } // check arrival delay in tvt if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) { for (i=0; i= 0 && Wings[TVT_wings[i]].arrival_delay > 0) { if (error("%s wing shouldn't have a non-zero arrival delay", TVT_wing_names[i])) return 1; } } } // check mixed-species in a wing for multi missions if (multi) { if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) { for (i=0; i= 0) { if (global_error_check_mixed_player_wing(TVT_wings[i])) return 1; } } } else { for (i=0; i= 0) { if (global_error_check_mixed_player_wing(Starting_wings[i])) return 1; } } } } for (i=0; i 2) starting_wing_list += ","; starting_wing_list += " "; } else { starting_wing_list += "or "; starting_wing_list += Starting_wing_names[i]; } } for (i=0; i 2) tvt_wing_list += ","; tvt_wing_list += " "; } else { tvt_wing_list += "or "; tvt_wing_list += TVT_wing_names[i]; } } // check players in wings ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { int ship_instance = ptr->instance; err = 0; // this ship is a player? if (ptr->type == OBJ_START) { // check if this ship is in a wing z = Ships[ship_instance].wingnum; if (z < 0) { err = 1; } else { int in_starting_wing = 0; int in_tvt_wing = 0; // check which wing the player is in for (i=0; i(tvt_wing_list))) return 1; } else { if (error("Player %s should be part of %s wing", Ships[ship_instance].ship_name, static_cast(starting_wing_list))) return 1; } } } ptr = GET_NEXT(ptr); } // check all wings in tvt have players if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) { for (i=0; i -100) err = 1; if (err) return internal_error("%s", error_buf.c_str()); if (error("%s", error_buf.c_str())) return 1; } z = 0; if (Error_checker_checks_potential_issues || Error_checker_checks_potential_issues_once) z = check_sexp_potential_issues(sexp, &faulty_node, issue_msg); if (z) { convert_sexp_to_string(sexp_buf, sexp, SEXP_ERROR_CHECK_MODE); truncate_message_lines(sexp_buf, 30); stuff_sexp_text_string(bad_node_str, faulty_node, SEXP_ERROR_CHECK_MODE); if (!bad_node_str.empty()) // the previous function adds a space at the end bad_node_str.pop_back(); sprintf(error_buf, "Potential issue detected in %s:\n\n%s\n\n%s\n\n(Suspect node appears to be: %s)", location_buf.c_str(), issue_msg.c_str(), sexp_buf.c_str(), bad_node_str.c_str()); if (Fred_main_wnd->MessageBox(error_buf.c_str(), "Warning", MB_OKCANCEL | MB_ICONINFORMATION) != IDOK) return 1; } Error_checker_checks_potential_issues_once = false; return 0; } void CFREDView::OnEditorsWaypoint() { Assert(Waypoint_editor_dialog.GetSafeHwnd()); if (!theApp.init_window(&Waypoint_wnd_data, &Waypoint_editor_dialog)) return; Waypoint_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Waypoint_editor_dialog.ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsJumpnode() { Assert(Jumpnode_editor_dialog.GetSafeHwnd()); if (!theApp.init_window(&Jumpnode_wnd_data, &Jumpnode_editor_dialog)) return; Jumpnode_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Jumpnode_editor_dialog.ShowWindow(SW_RESTORE); } char *error_check_initial_orders(ai_goal *goals, int ship, int wing) { char *source; int i, j, num, flag, found, inst, team, team2; object *ptr; if (ship >= 0) { source = Ships[ship].ship_name; team = Ships[ship].team; for (i=0; ierror("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode), source)) return "!"; } } else { Assert(wing >= 0); Assert(Wings[wing].wave_count > 0); source = Wings[wing].name; team = Ships[Objects[wing_objects[wing][0]].instance].team; for (j=0; jerror("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode), Ships[Wings[wing].ship_index[j]].ship_name)) return "!"; } } for (i=0; i 0) { if (*goals[i].target_name == '<') return "Invalid target"; if (!stricmp(goals[i].target_name, source)) if (ship >= 0) return "Target of ship's goal is itself"; else return "Target of wing's goal is itself"; } inst = team2 = -1; if (flag == 1) { // target waypoint required if (find_matching_waypoint_list(goals[i].target_name) == NULL) return "*Invalid target waypoint path name"; } else if (flag == 2) { // target ship required ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) { inst = ptr->instance; if (!stricmp(goals[i].target_name, Ships[inst].ship_name)) { found = 1; break; } } ptr = GET_NEXT(ptr); } if (!found) return "*Invalid target ship name"; if (wing >= 0) { // check if target ship is in wing if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START) return "Target ship of wing's goal is within said wing"; } team2 = Ships[inst].team; } else if (flag == 3) { // target wing required for (j=0; j= MAX_WINGS) return "*Invalid target wing name"; if (ship >= 0) { // check if ship is in target wing if (Ships[ship].wingnum == j) return "Target wing of ship's goal is same wing said ship is part of"; } team2 = Ships[Objects[wing_objects[j][0]].instance].team; } else if (flag == 4) { ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) { inst = ptr->instance; if (!stricmp(goals[i].target_name, Ships[inst].ship_name)) { found = 2; break; } } else if (ptr->type == OBJ_WAYPOINT) { if (!stricmp(goals[i].target_name, object_name(OBJ_INDEX(ptr)))) { found = 1; break; } } ptr = GET_NEXT(ptr); } if (!found) return "*Invalid target ship or waypoint name"; if (found == 2) { if (wing >= 0) { // check if target ship is in wing if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START) return "Target ship of wing's goal is within said wing"; } team2 = Ships[inst].team; } } switch (goals[i].ai_mode) { case AI_GOAL_DESTROY_SUBSYSTEM: Assert(flag == 2 && inst >= 0); if (ship_find_subsys(&Ships[inst], goals[i].docker.name) < 0) return "Unknown subsystem type"; break; case AI_GOAL_DOCK: { int dock1 = -1, dock2 = -1, model1, model2; Assert(flag == 2 && inst >= 0); if (!ship_docking_valid(ship, inst)) return "Docking illegal between given ship types"; model1 = Ship_info[Ships[ship].ship_info_index].model_num; num = get_docking_list(model1); for (j=0; j= 0) && (dock2 >= 0)) { if ( !(model_get_dock_index_type(model1, dock1) & model_get_dock_index_type(model2, dock2)) ) return "Dock points are incompatible"; } break; } } switch (goals[i].ai_mode) { case AI_GOAL_GUARD: case AI_GOAL_GUARD_WING: if (team != team2) { // MK, added support for TEAM_NEUTRAL. Won't this work? if (ship >= 0) return "Ship assigned to guard a different team"; else return "Wing assigned to guard a different team"; } break; case AI_GOAL_CHASE: case AI_GOAL_CHASE_WING: case AI_GOAL_DESTROY_SUBSYSTEM: case AI_GOAL_DISARM_SHIP: case AI_GOAL_DISARM_SHIP_TACTICAL: case AI_GOAL_DISABLE_SHIP: case AI_GOAL_DISABLE_SHIP_TACTICAL: if (team == team2) { if (ship >= 0) return "Ship assigned to attack same team"; else return "Wings assigned to attack same team"; } break; } } return NULL; } // function (which is called externally from message editor and event editor) so skip through // the sexpression nodes to look for send-message commands to try to associate message personas // to ships void fred_check_message_personas() { /* int i, op, j, ship_index; char *mname, *who_from; object *objp; // this function is responsible for assigning personas to ships as well as error checking them. // clear out the persona index on all ship objects for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) { if ( objp->type == OBJ_SHIP ) { Ships[objp->instance].persona_index = -1; } } for (i = 0; i < Num_sexp_nodes; i++ ) { if ( Sexp_nodes[i].type == SEXP_NOT_USED ) continue; // look for only operator nodes if ( Sexp_nodes[i].subtype != SEXP_ATOM_OPERATOR ) continue; // now look for the send-message opeator op = get_operator_const( i ); if ( op != OP_SEND_MESSAGE ) continue; // have the message. parse through the message to determine who is sending the message. who_from = CTEXT(CDR(i)); // we can ignore messages from any wingman, and allied, or from God. if ( !stricmp(who_from, "") || !stricmp(who_from, "") || (who_from[0] == '#') ) continue; mname = CTEXT(CDR(CDR(CDR(i)))); // check to see if who_from is a wing. Don't do processing if so. if ( wing_name_lookup(who_from, 1) != -1 ) continue; ship_index = ship_name_lookup( who_from ); if ( ship_index == -1 ) { Int3(); // get allender. something funny is up with shipnames in send-message continue; } for ( j = Num_builtin_messages; j < Num_messages; j++ ) { if ( !stricmp(mname, Messages[j].name) ) { // check to see if there is a persona for this message -- if not, bail if ( Messages[j].persona_index == -1 ) break; // if a ship isn't assigned a persona, and this message says that he is, assign it, and move on if ( Ships[ship_index].persona_index == -1 ) { Ships[ship_index].persona_index = Messages[j].persona_index; continue; } // we must be sure of the following conditions: // 1) a ship isn't assigned > 1 persona if ( Ships[ship_index].persona_index != Messages[j].persona_index ) 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 ); } } } // check that two or more ships are not using the same persona for (i = 0; i < Num_personas; i++ ) { int persona_count; object *objp; // move through object list looking for number of shis using this persona persona_count = 0; for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) { if ( objp->type != OBJ_SHIP ) continue; if (Ships[objp->instance].persona_index == i ) persona_count++; } if ( persona_count > 1 ) Fred_view_wnd->error("Persona %s used by more than 1 ship", Personas[Messages[j].persona_index].name ); } */ } void CFREDView::OnViewOutlines() { Show_outlines = !Show_outlines; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateViewOutlines(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_outlines); } void CFREDView::OnViewOutlinesOnSelected() { Draw_outlines_on_selected_ships = !Draw_outlines_on_selected_ships; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateViewOutlinesOnSelected(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Draw_outlines_on_selected_ships); } void CFREDView::OnViewOutlineAtWarpin() { Draw_outline_at_warpin_position = !Draw_outline_at_warpin_position; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateViewOutlineAtWarpin(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Draw_outline_at_warpin_position); } void CFREDView::OnMiscRotateSelectionMidpoint() { Orbit_selection_midpoint = !Orbit_selection_midpoint; Orbit_active = false; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateMiscRotateSelectionMidpoint(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Orbit_selection_midpoint); } void CFREDView::OnAlwaysSaveDisplayNames() { Always_save_display_names = !Always_save_display_names; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateAlwaysSaveDisplayNames(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Always_save_display_names); } void CFREDView::OnErrorCheckerChecksPotentialIssues() { Error_checker_checks_potential_issues = !Error_checker_checks_potential_issues; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateErrorCheckerChecksPotentialIssues(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Error_checker_checks_potential_issues); } void CFREDView::OnClassicMenuLayout() { Classic_menu_layout = !Classic_menu_layout; if (Fred_main_wnd != nullptr) Fred_main_wnd->apply_menu_layout(Classic_menu_layout); theApp.write_ini_file(); } void CFREDView::OnUpdateClassicMenuLayout(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Classic_menu_layout); } void CFREDView::OnUpdateNewShipType(CCmdUI* pCmdUI) { int z; CWnd *bar; z = m_new_ship_type_combo_box.GetCurSel(); if (z == CB_ERR) m_new_ship_type_combo_box.SetCurSel(cur_ship_type_combo_index); else cur_ship_type_combo_index = z; bar = GetDlgItem(pCmdUI->m_nID); if (!bar) { pCmdUI -> ContinueRouting(); return; // not for us } pCmdUI -> SetCheck((bar->GetStyle() & WS_VISIBLE) != 0); } void CFREDView::OnShowStarfield() { Show_stars = !Show_stars; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowStarfield(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_stars); } void CFREDView::OnAsteroidEditor() { asteroid_editor dlg; dlg.DoModal(); } void CFREDView::OnRunFreeSpace() { BOOL r = FALSE; STARTUPINFO si; PROCESS_INFORMATION pi; char *lpMsgBuf; if (!FREDDoc_ptr->SaveModified()) return; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); si.lpReserved = nullptr; si.lpDesktop = nullptr; si.lpTitle = nullptr; si.dwFlags = 0; si.cbReserved2 = 0; si.lpReserved2 = nullptr; // get the filename of the app and replace FRED2_Open with FS2_Open SCP_string processed_name(AfxGetApp()->m_pszExeName); SCP_string processed_lowername = processed_name; SCP_tolower(processed_lowername); SCP_string::size_type fred_index = processed_lowername.find("fred2_open", 0); // capitalisation! bool capitalF = false; if (fred_index != SCP_string::npos && processed_name[fred_index] == 'F') { capitalF = true; } SCP_vector nameAttempts; if (fred_index != std::string::npos) { // replace fred2_open with fs2_open processed_name.erase(fred_index, 4); processed_name.insert(fred_index, capitalF ? "FS" : "fs"); processed_name.append(".exe"); nameAttempts.push_back(processed_name); } nameAttempts.push_back("fs2_open.exe"); nameAttempts.push_back("fs2_open_r.exe"); // reconstruct command line extern SCP_string cmdline_build_string(); auto commandArgs = cmdline_build_string(); for (const auto &nameAttempt: nameAttempts) { // CreateProcess actually writes to the C-string, so we have to make it modifiable std::unique_ptr fullString(new char[nameAttempt.length() + commandArgs.length() + 1]); strcpy(fullString.get(), nameAttempt.c_str()); strcat(fullString.get(), commandArgs.c_str()); // try to start FS2_open r = CreateProcess(nullptr, fullString.get(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi); if (r) { break; } } if (r) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the string. MessageBox(lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); } } void CFREDView::OnEditorCampaign() { if (!FREDDoc_ptr->SaveModified()) return; Assert(!Campaign_wnd); Campaign_wnd = new campaign_tree_wnd; if (Campaign_wnd->Create(NULL, "Campaign Editor", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE, CFrameWnd::rectDefault, NULL, "IDR_MENU_CAMPAIGN")) { Campaign_wnd->ShowWindow(SW_SHOW); Campaign_wnd->UpdateWindow(); } } void CFREDView::OnShowShips() { Show_ships = !Show_ships; correct_marking(); Update_window = 1; } void CFREDView::OnUpdateShowShips(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_ships); } void CFREDView::OnShowStarts() { Show_starts = !Show_starts; correct_marking(); Update_window = 1; } void CFREDView::OnUpdateShowStarts(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_starts); } void CFREDView::OnShowIFF(int iff) { Show_iff[iff] = !Show_iff[iff]; correct_marking(); Update_window = 1; } void CFREDView::OnUpdateShowIFF(int iff, CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_iff[iff]); } void CFREDView::OnToggleViewpoint() { if (viewpoint || !query_valid_object()) viewpoint = 0; else { viewpoint = 1; view_obj = cur_object_index; } Update_window = 1; } void CFREDView::OnRevert() { if (!FREDDoc_ptr->SaveModified()) return; FREDDoc_ptr->DeleteContents(); FREDDoc_ptr->OnOpenDocument(NULL); } void CFREDView::OnUpdateRevert(CCmdUI* pCmdUI) { pCmdUI->Enable(*Mission_filename); } BOOL CFREDView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if ((Cursor_over >= 0) || Selection_lock) { if (Editing_mode == 1) { SetCursor(h_cursor_move); return TRUE; } else if (Editing_mode == 2) { SetCursor(h_cursor_rotate); return TRUE; } } return CView::OnSetCursor(pWnd, nHitTest, message); } void CFREDView::OnHideMarkedObjects() { object *ptr; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->flags[Object::Object_Flags::Marked]) { ptr->flags.set(Object::Object_Flags::Hidden); unmark_object(OBJ_INDEX(ptr)); } ptr = GET_NEXT(ptr); } } void CFREDView::OnShowHiddenObjects() { object *ptr; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { ptr->flags.remove(Object::Object_Flags::Hidden); ptr = GET_NEXT(ptr); } Update_window = 1; } void CFREDView::OnLockMarkedObjects() { object *ptr; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->flags[Object::Object_Flags::Marked]) { ptr->flags.set(Object::Object_Flags::Locked_from_editing); unmark_object(OBJ_INDEX(ptr)); } ptr = GET_NEXT(ptr); } } void CFREDView::OnUnlockAllObjects() { object *ptr; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { ptr->flags.remove(Object::Object_Flags::Locked_from_editing); ptr = GET_NEXT(ptr); } Update_window = 1; } void CFREDView::OnEditUndo() { vec3d viewer_pos; matrix viewer_orient; if (Undo_available) { viewer_pos = view_pos; viewer_orient = view_orient; FREDDoc_ptr->autoload(); view_pos = viewer_pos; view_orient = viewer_orient; } } void CFREDView::OnUpdateEditUndo(CCmdUI* pCmdUI) { pCmdUI->Enable(Undo_available); } void CFREDView::OnEditorsBriefing() { if (!Briefing_dialog) { Briefing_dialog = new briefing_editor_dlg; Briefing_dialog->create(); } Briefing_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Briefing_dialog->ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsDebriefing() { if (!Debriefing_dialog) { Debriefing_dialog = new debriefing_editor_dlg; Debriefing_dialog->create(); } Debriefing_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Debriefing_dialog->ShowWindow(SW_RESTORE); } void CFREDView::OnSaveCamera() { saved_cam_pos = view_pos; saved_cam_orient = view_orient; } void CFREDView::OnRestoreCamera() { view_pos = saved_cam_pos; view_orient = saved_cam_orient; Update_window = 1; } void CFREDView::OnUpdateRestoreCamera(CCmdUI* pCmdUI) { pCmdUI->Enable(!IS_VEC_NULL(&saved_cam_orient.vec.fvec)); } void CFREDView::OnShowSexpHelp() { CRect rect; Show_sexp_help = !Show_sexp_help; Ship_editor_dialog.show_hide_sexp_help(); Wing_editor_dialog.show_hide_sexp_help(); } void CFREDView::OnUpdateShowSexpHelp(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_sexp_help); } void CFREDView::OnLookatObj() { Lookat_mode = !Lookat_mode; if (Lookat_mode && query_valid_object()) { vec3d v, loc; matrix m; loc = selection_midpoint(); vm_vec_sub(&v, &loc, &view_pos); if (v.xyz.x || v.xyz.y || v.xyz.z) { vm_vector_2_matrix(&m, &v, NULL, NULL); view_orient = m; } } } void CFREDView::OnUpdateLookatObj(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Lookat_mode); } void CFREDView::OnGroup(UINT nID) { int n = 1 << (nID - ID_GROUP1); object *objp; unmark_all(); objp = GET_FIRST(&obj_used_list); while (objp != END_OF_LIST(&obj_used_list)) { if (objp->type == OBJ_SHIP) { if (Ships[objp->instance].group & n) mark_object(OBJ_INDEX(objp)); } objp = GET_NEXT(objp); } Update_window = 1; } void CFREDView::OnSetGroup(UINT nID) { int i, err = 0, n = 1 << (nID - ID_SET_GROUP1); object *objp; for (i=0; iflags[Object::Object_Flags::Marked]) { if (objp->type == OBJ_SHIP) { Ships[objp->instance].group |= n; } else err = 1; } objp = GET_NEXT(objp); } if (err) Fred_main_wnd->MessageBox("Only ships can be in groups, and not players or waypoints, etc.\n" "These illegal objects you marked were not placed in the group"); Update_window = 1; } void CFREDView::OnEditorsAdjustGrid() { adjust_grid_dlg dlg; dlg.DoModal(); Update_window = 1; } void CFREDView::OnCalcRelativeCoords() { calc_relative_coords_dlg dlg; dlg.DoModal(); } void CFREDView::OnReorder() { reorder_dlg dlg; dlg.DoModal(); } void CFREDView::OnMusicPlayer() { Assertion(Music_player_dialog.GetSafeHwnd(), "Unable to create music player window!"); if (!theApp.init_window(&MusPlayer_wnd_data, &Music_player_dialog)) return; Music_player_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); Music_player_dialog.ShowWindow(SW_RESTORE); } void CFREDView::OnEditorsShieldSys() { shield_sys_dlg dlg; dlg.DoModal(); } void CFREDView::OnLevelObj() { level_controlled(); Update_window = 1; } void CFREDView::OnAlignObj() { verticalize_controlled(); Update_window = 1; } void CFREDView::OnControlObj() { Control_mode = (Control_mode + 1) % 2; } void CFREDView::OnNextObj() { object *ptr; if (Bg_bitmap_dialog) { if (Cur_bitmap == -1) { if (stars_get_num_bitmaps()) { Cur_bitmap = 0; Bg_bitmap_dialog -> update_data(); } return; } Cur_bitmap++; if (Cur_bitmap >= stars_get_num_bitmaps()) Cur_bitmap = 0; Bg_bitmap_dialog -> update_data(); return; } if (EMPTY(&obj_used_list)) return; if (query_valid_object()) { ptr = Objects[cur_object_index].next; if (ptr == END_OF_LIST(&obj_used_list)) ptr = GET_NEXT(ptr); } else ptr = GET_FIRST(&obj_used_list); if (Marked > 1) { // cycle through marked list while (!(ptr->flags[Object::Object_Flags::Marked])) { ptr = GET_NEXT(ptr); if (ptr == END_OF_LIST(&obj_used_list)) ptr = GET_NEXT(ptr); } set_cur_object_index(OBJ_INDEX(ptr)); } else { if (Marked) unmark_object(cur_object_index); mark_object(OBJ_INDEX(ptr)); } } void CFREDView::OnPrevObj() { int arr[MAX_OBJECTS], i = 0, n = 0; object *ptr; if (Bg_bitmap_dialog) { if (Cur_bitmap == -1) { if (stars_get_num_bitmaps()) { Cur_bitmap = stars_get_num_bitmaps() - 1; Bg_bitmap_dialog -> update_data(); } return; } Cur_bitmap--; if (Cur_bitmap < 0) Cur_bitmap = stars_get_num_bitmaps() - 1; Bg_bitmap_dialog -> update_data(); return; } if (EMPTY(&obj_used_list)) return; ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (cur_object_index == OBJ_INDEX(ptr)) i = n; arr[n++] = OBJ_INDEX(ptr); ptr = GET_NEXT(ptr); } Assert(n); if (query_valid_object()) { i--; if (i < 0) i = n - 1; } else i = n - 1; if (Marked > 1) { // cycle through marked list while (!(Objects[i].flags[Object::Object_Flags::Marked])) { i--; if (i < 0) i = n - 1; } set_cur_object_index(i); } else { if (Marked) unmark_object(cur_object_index); mark_object(i); } } void CFREDView::OnEditDelete() { if (!button_down && Marked) { delete_marked(); FREDDoc_ptr->autosave("object delete"); } Update_window = 2; // For some strange reason, need to redraw twice for it to take. } void CFREDView::OnEditCloneMarkedObjects() { if (!button_down && Marked) { duplicate_marked_objects(); FREDDoc_ptr->autosave("clone marked"); } Update_window = 1; } void CFREDView::OnEditDeleteWing() { if (!button_down && (cur_wing >= 0)) { delete_wing(); FREDDoc_ptr->autosave("wing delete"); cur_wing = -1; if (!Marked) Ship_editor_dialog.initialize_data(1); Wing_editor_dialog.initialize_data(1); } Update_window = 2; // For some strange reason, need to redraw twice for it to take. } void CFREDView::OnMarkWing() { int i, wing = cur_wing; if (wing != -1) { unmark_all(); for (i=0; i= 0 && Wings[wing].special_ship < Wings[wing].wave_count); set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]); } } void CFREDView::OnUpdateControlObj(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Control_mode != 0); } void CFREDView::OnAaGridlines() { Aa_gridlines = !Aa_gridlines; } void CFREDView::OnUpdateAaGridlines(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Aa_gridlines); Update_window = 1; } void CFREDView::OnCmdBrief() { cmd_brief_dlg dlg; dlg.DoModal(); Update_window = 1; } void CFREDView::OnDisableUndo() { Autosave_disabled = !Autosave_disabled; } void CFREDView::OnUpdateDisableUndo(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Autosave_disabled); } void CFREDView::OnUpdateCmdBrief(CCmdUI* pCmdUI) { pCmdUI->Enable(true); } int get_visible_sub_system_count(ship *shipp) { int count = 0; ship_subsys *cur_subsys; for (cur_subsys = GET_FIRST(&shipp->subsys_list); cur_subsys != END_OF_LIST(&shipp->subsys_list); cur_subsys = GET_NEXT(cur_subsys)) { if (cur_subsys->system_info->subobj_num != -1) { count++; } } return count; } int get_next_visible_subsys(ship *shipp, ship_subsys **next_subsys) { int count = get_visible_sub_system_count(shipp); // return don't try to display if (count == 0) { return 0; } // first timer if (*next_subsys == NULL) { *next_subsys = &shipp->subsys_list; } // look before wrap for (*next_subsys = GET_NEXT(*next_subsys); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) { if ((*next_subsys)->system_info->subobj_num != -1) { Update_window = 1; return 1; } } // look for first after wrap for (*next_subsys = GET_FIRST(&shipp->subsys_list); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) { if ((*next_subsys)->system_info->subobj_num != -1) { Update_window = 1; return 1; } } Int3(); // should be impossible to miss return 0; } int get_prev_visible_subsys(ship *shipp, ship_subsys **prev_subsys) { int count = get_visible_sub_system_count(shipp); // return don't try to display if (count == 0) { return 0; } // first timer Assert(*prev_subsys != NULL); // look before wrap for (*prev_subsys = GET_PREV(*prev_subsys); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) { if ((*prev_subsys)->system_info->subobj_num != -1) { Update_window = 1; return 1; } } // look for first after wrap for (*prev_subsys = GET_LAST(&shipp->subsys_list); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) { if ((*prev_subsys)->system_info->subobj_num != -1) { Update_window = 1; return 1; } } Int3(); // should be impossible to miss return 0; } // update next subsystem to view void CFREDView::OnNextSubsys() { object *objp; if (cur_object_index < 0) { OnCancelSubsys(); } objp = &Objects[cur_object_index]; // check if cur object is ship type if (objp->type == OBJ_SHIP) { // check if same ship if (Render_subsys.ship_obj == objp) { // if already on, advance to next if (Render_subsys.do_render) { if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) { OnCancelSubsys(); } } else { Int3(); } } else { // clean up OnCancelSubsys(); // set up new and advance to first Render_subsys.do_render = true; Render_subsys.ship_obj = objp; if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) { OnCancelSubsys(); } } } else { // not ship type OnCancelSubsys(); } } void CFREDView::OnPrevSubsys() { if (!Render_subsys.do_render) { return; } if ( (cur_object_index < 0) || (Objects[cur_object_index].type != OBJ_SHIP) || (&Objects[cur_object_index] != Render_subsys.ship_obj) ) { OnCancelSubsys(); return; } if ( !get_prev_visible_subsys(&Ships[Objects[cur_object_index].instance], &Render_subsys.cur_subsys) ) { OnCancelSubsys(); } } void CFREDView::OnCancelSubsys() { Render_subsys.do_render = false; Render_subsys.ship_obj = NULL; Render_subsys.cur_subsys = NULL; Update_window = 1; } void CFREDView::OnShowPaths() { Show_paths_fred = !Show_paths_fred; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowPaths(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_paths_fred); } void CFREDView::OnShowDockPoints() { Show_dock_points = !Show_dock_points; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateShowDockPoints(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Show_dock_points); } void CFREDView::OnMoveShipsWhenUndocking() { Move_ships_when_undocking = !Move_ships_when_undocking; theApp.write_ini_file(); } void CFREDView::OnUpdateMoveShipsWhenUndocking(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Move_ships_when_undocking); } void CFREDView::OnPointUsingUvec() { Point_using_uvec = !Point_using_uvec; theApp.write_ini_file(); } void CFREDView::OnUpdatePointUsingUvec(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Point_using_uvec); } void CFREDView::OnHighlightSubsys() { Highlight_selectable_subsys = !Highlight_selectable_subsys; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateHighlightSubsys(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Highlight_selectable_subsys); } void CFREDView::OnDumpStats() { DumpStats dlg; dlg.DoModal(); } void CFREDView::OnFormatFs2Open() { Mission_save_format = FSO_FORMAT_STANDARD; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateFormatFs2Open(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Mission_save_format == FSO_FORMAT_STANDARD); } void CFREDView::OnFormatFs2OpenComp() { Mission_save_format = FSO_FORMAT_COMPATIBILITY_MODE; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateFormatFs2OpenComp(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Mission_save_format == FSO_FORMAT_COMPATIBILITY_MODE); } void CFREDView::OnFormatFs2Retail() { Mission_save_format = FSO_FORMAT_RETAIL; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateFormatFs2Retail(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Mission_save_format == FSO_FORMAT_RETAIL); } void CFREDView::OnFormatFs1Retail() { Mission_save_format = FSO_FORMAT_RETAIL; theApp.write_ini_file(); Update_window = 1; } void CFREDView::OnUpdateFormatFs1Retail(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Mission_save_format == FSO_FORMAT_RETAIL); } void CFREDView::OnEditorsSetGlobalShipFlags() { SetGlobalShipFlags dlg; dlg.DoModal(); } void CFREDView::OnEditorsVoiceManager() { VoiceActingManager dlg; dlg.DoModal(); } void CFREDView::OnEditorsFiction() { FictionViewerDlg dlg; dlg.DoModal(); } void CFREDView::OnDestroy() { audiostream_close(); snd_close(); CView::OnDestroy(); } int CFREDView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; MoveWindow(0,0,200,300,1); std::unique_ptr graphicsOperations(new MFCGraphicsOperations(this->GetSafeHwnd())); if(fred_init(std::move(graphicsOperations)) == false) return -1; return 0; } BOOL CFREDView::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CFREDView::OnViewLighting() { Lighting_on = !Lighting_on; } void CFREDView::OnUpdateViewLighting(CCmdUI* pCmdUI) { pCmdUI->SetCheck(Lighting_on); } void CFREDView::OnViewFullDetail() { FullDetail = !FullDetail; } void CFREDView::OnUpdateViewFullDetail(CCmdUI *pCmdUI) { pCmdUI->SetCheck(FullDetail); } BOOL CFREDView::DestroyWindow() { Fred_view_wnd = nullptr; return CView::DestroyWindow(); } void CFREDView::OnShowIFF0() { OnShowIFF(0); } void CFREDView::OnUpdateShowIFF0(CCmdUI* pCmdUI) { OnUpdateShowIFF(0, pCmdUI); } void CFREDView::OnShowIFF1() { OnShowIFF(1); } void CFREDView::OnUpdateShowIFF1(CCmdUI* pCmdUI) { OnUpdateShowIFF(1, pCmdUI); } void CFREDView::OnShowIFF2() { OnShowIFF(2); } void CFREDView::OnUpdateShowIFF2(CCmdUI* pCmdUI) { OnUpdateShowIFF(2, pCmdUI); } void CFREDView::OnShowIFF3() { OnShowIFF(3); } void CFREDView::OnUpdateShowIFF3(CCmdUI* pCmdUI) { OnUpdateShowIFF(3, pCmdUI); } void CFREDView::OnShowIFF4() { OnShowIFF(4); } void CFREDView::OnUpdateShowIFF4(CCmdUI* pCmdUI) { OnUpdateShowIFF(4, pCmdUI); } void CFREDView::OnShowIFF5() { OnShowIFF(5); } void CFREDView::OnUpdateShowIFF5(CCmdUI* pCmdUI) { OnUpdateShowIFF(5, pCmdUI); } void CFREDView::OnShowIFF6() { OnShowIFF(6); } void CFREDView::OnUpdateShowIFF6(CCmdUI* pCmdUI) { OnUpdateShowIFF(6, pCmdUI); } void CFREDView::OnShowIFF7() { OnShowIFF(7); } void CFREDView::OnUpdateShowIFF7(CCmdUI* pCmdUI) { OnUpdateShowIFF(7, pCmdUI); } void CFREDView::OnShowIFF8() { OnShowIFF(8); } void CFREDView::OnUpdateShowIFF8(CCmdUI* pCmdUI) { OnUpdateShowIFF(8, pCmdUI); } void CFREDView::OnShowIFF9() { OnShowIFF(9); } void CFREDView::OnUpdateShowIFF9(CCmdUI* pCmdUI) { OnUpdateShowIFF(9, pCmdUI); }