mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
* qtFRED: rotate around the centre of a multi-selection Rotate Around Object (Alt+R) and the orbit pivot both used the current object's position, so with several ships marked the camera still circled whichever one happened to be current. Add EditorViewport::selectionCenter(), which returns the centroid of the marked objects when more than one is marked and the given object's position otherwise, and use it at the three places that chose the point: the look-at camera update, orbitCameraGetPivot(), and the Alt+R handler that turns the camera toward the target when the mode is switched on. orbitCameraGetPivot() also serves middle-mouse orbit and wheel zoom in normal mode, so those pivot on the selection centre as well. Every marked type counts at full weight, including waypoints and jump nodes. With a single object marked nothing changes. Fixes #7724 * Make EditorViewport::selectionCenter const It only reads the marked-object list and the editor's marked count; clang-tidy (readability-make-member-function-const) flagged it in CI. * Mirror the multi-selection orbit pivot to FRED, trim comments FRED gets the same selection_center() as qtFRED's selectionCenter(), used at the same three places: the look-at camera update, the orbit pivot, and the Rotate Around Object toggle. Also removes the qtFRED comments flagged in review. * Make the selection-center pivot optional and share object bounds Look-at and orbit use the current object again unless the new option is on (qtFRED: Preferences > Controls; FRED: View menu), and the selection center is now the bounding-box midpoint. view_universe in both editors, the pivot, and qtFRED's selection radius all use get_object_bounds() in missioneditor/common. * Reset the cached orbit pivot when the selection-center option changes Wheel zoom reuses the orbit pivot until the camera moves, so without this the option only took effect for scrolling after the next camera move. * Address review: move and rename the selection-centroid option - FRED: the option moves from the View menu to Settings (and Misc in the classic layout), under Move Ships When Undocking, with hover help, and is renamed Rotate Around Selection Centroid. - qtFRED: the checkbox moves next to Move Ships When Undocking in the preferences dialog, with the same name. - setOrbitSelectionCenter only resets the orbit when the value changes. - get_object_bounds iterates with list_range. - The bounds test resets the object system with obj_init and takes objects off the free list, so it leaves a valid state for other tests. * Rename the option to Selection Midpoint, move it to qtFRED's Controls tab, and document it * Fix overlapping Appearance rows in qtFRED Preferences, realign a settings line The last commit renumbered the Viewport label size row of the Appearance group from 4 to 3, which is the Long list menu style row, so the label size pair fell out of the layout and its spin box drew over the group title. Put it back at row 4. --------- Co-authored-by: Dustinspace217 <[email protected]>
5236 lines
130 KiB
C++
5236 lines
130 KiB
C++
/*
|
|
* 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<int> 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; i<Species_info.size(); i++) {
|
|
species_submenu[i].CreatePopupMenu();
|
|
shipPopup.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
|
|
(UINT) species_submenu[i].m_hMenu, Species_info[i].species_name);
|
|
}
|
|
|
|
i = 0;
|
|
for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
|
|
if (it->flags[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<int>(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<obj_count; z++)
|
|
if (flags[z])
|
|
delete [] names[z];
|
|
|
|
obj_count = 0;
|
|
}
|
|
|
|
int CFREDView::global_error_check()
|
|
{
|
|
char buf[256], *str;
|
|
int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
|
|
object *ptr;
|
|
brief_stage *sp;
|
|
SCP_string anchor_message;
|
|
SCP_set<anchor_t> 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<MAX_SHIP_PRIMARY_BANKS; n++){
|
|
if (Ships[i].weapons.primary_bank_weapons[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<MAX_SHIP_SECONDARY_BANKS; n++){
|
|
if (Ships[i].weapons.secondary_bank_weapons[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<obj_count; i++){
|
|
if (names[i] && names[obj_count]){
|
|
if (!stricmp(names[i], names[obj_count])){
|
|
return internal_error("Duplicate object names (%s)", names[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
obj_count++;
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
if (t != Player_starts){
|
|
return internal_error("Total number of player ships is incorrect");
|
|
}
|
|
|
|
if (obj_count != Num_objects){
|
|
return internal_error("Num_objects is incorrect");
|
|
}
|
|
|
|
count = 0;
|
|
for (i=0; i<MAX_SHIPS; i++) {
|
|
if (Ships[i].objnum >= 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_WINGS; i++) {
|
|
team = -1;
|
|
j = Wings[i].wave_count;
|
|
if (j) { // is wing being used?
|
|
count++;
|
|
if (j < 0 || j > 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; j<obj_count; j++){
|
|
if (names[j]){
|
|
if (!stricmp(names[j], Wings[i].name)){
|
|
return internal_error("Wing name is also used by an object (%s)", names[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(fred_check_sexp(Wings[i].arrival_cue, OPR_BOOL, "arrival cue of wing \"%s\"", Wings[i].name)){
|
|
return -1;
|
|
}
|
|
|
|
if(fred_check_sexp(Wings[i].departure_cue, OPR_BOOL, "departure cue of wing \"%s\"", Wings[i].name)){
|
|
return -1;
|
|
}
|
|
|
|
if (Wings[i].arrival_location != ArrivalLocation::AT_LOCATION) {
|
|
if (!Wings[i].arrival_anchor.isValid())
|
|
if (error("Wing \"%s\" requires a valid arrival target", Wings[i].name))
|
|
return 1;
|
|
if (Wings[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) {
|
|
check_anchor_for_hangar_bay(anchor_message, anchors_checked, Wings[i].arrival_anchor, Wings[i].name, false, true);
|
|
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Wings[i].departure_location != DepartureLocation::AT_LOCATION) {
|
|
if (!Wings[i].departure_anchor.isValid())
|
|
if (error("Wing \"%s\" requires a valid departure target", Wings[i].name))
|
|
return 1;
|
|
if (Wings[i].departure_location == DepartureLocation::TO_DOCK_BAY) {
|
|
check_anchor_for_hangar_bay(anchor_message, anchors_checked, Wings[i].departure_anchor, Wings[i].name, false, false);
|
|
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i))>0) {
|
|
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<obj_count; z++){
|
|
if (names[z]){
|
|
if (!stricmp(names[z], ii.get_name())){
|
|
return internal_error("Waypoint path name is also used by an object (%s)", names[z]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const auto &jj: ii.get_waypoints()) {
|
|
waypoint_stuff_name(buf, jj);
|
|
for (z=0; z<obj_count; z++){
|
|
if (names[z]){
|
|
if (!stricmp(names[z], buf)){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (z == obj_count){
|
|
return internal_error("Waypoint \"%s\" not linked to an object", buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Player_starts > 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<MAX_SHIPS; ship++){
|
|
if ((Ships[ship].objnum >= 0) && !stricmp(Ships[ship].ship_name, reinforcement.name)) {
|
|
z = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (wing=0; wing<MAX_WINGS; wing++){
|
|
if (Wings[wing].wave_count && !stricmp(Wings[wing].name, reinforcement.name)) {
|
|
z = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!z){
|
|
return internal_error("Reinforcement name not found in ships or wings");
|
|
}
|
|
}
|
|
|
|
/* for (i=0; i<num_messages; i++) {
|
|
if (Messages[i].num_times < 0)
|
|
return internal_error("Number of times to play message is negative");
|
|
|
|
z = Messages[i].who_from;
|
|
if (z < -1 || z >= 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; s<Briefings[bs].num_stages; s++) {
|
|
sp = &Briefings[bs].stages[s];
|
|
t = sp->num_icons;
|
|
for (i=0; i<t-1; i++){
|
|
for (j=i+1; j<t; j++) {
|
|
if ((sp->icons[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<Debriefings[j].num_stages; i++) {
|
|
if (fred_check_sexp(Debriefings[j].stages[i].formula, OPR_BOOL, "debriefing stage %d", i + 1)){
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// for all wings, be sure that the orders accepted for all ships are the same for all ships
|
|
// in the wing
|
|
//std::set<size_t> starting_orders { std::numeric_limits<size_t>::max() };
|
|
for (i=0; i<MAX_WINGS; i++) {
|
|
int starting_wing;
|
|
std::set<size_t> 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<size_t> 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<Wings[w].wave_count; i++) {
|
|
s = Wings[w].ship_index[i];
|
|
if (species < 0)
|
|
species = Ship_info[Ships[s].ship_info_index].species;
|
|
else if (Ship_info[Ships[s].ship_info_index].species != species)
|
|
mixed = 1;
|
|
}
|
|
|
|
if (mixed)
|
|
if (error("%s wing must all be of the same species", Wings[w].name))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CFREDView::global_error_check_player_wings(int multi)
|
|
{
|
|
int i, z, err;
|
|
int starting_wing_count[MAX_STARTING_WINGS];
|
|
int tvt_wing_count[MAX_TVT_WINGS];
|
|
|
|
object *ptr;
|
|
CString starting_wing_list = "";
|
|
CString tvt_wing_list = "";
|
|
|
|
// check team wings in tvt
|
|
if ( multi && The_mission.game_type & MISSION_TYPE_MULTI_TEAMS )
|
|
{
|
|
for (i=0; i<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (ship_tvt_wing_lookup(TVT_wing_names[i]) == -1)
|
|
{
|
|
if (error("%s wing is required for multiplayer team vs. team missions"))
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The wing containing the player start must be present at mission start, so a custom arrival cue
|
|
// is only useful for controlling the arrival of subsequent waves. Flag a single-wave wing with a
|
|
// custom cue as a potential issue, but never change the cue itself.
|
|
if (Error_checker_checks_potential_issues || Error_checker_checks_potential_issues_once)
|
|
{
|
|
for (i=0; i<MAX_WINGS; i++)
|
|
{
|
|
if (!Wings[i].wave_count || Wings[i].num_waves > 1)
|
|
continue;
|
|
if (Wings[i].arrival_cue == Locked_sexp_true)
|
|
continue;
|
|
|
|
bool contains_player_start = false;
|
|
for (z=0; z<Wings[i].wave_count; z++)
|
|
if (Objects[Ships[Wings[i].ship_index[z]].objnum].type == OBJ_START)
|
|
contains_player_start = true;
|
|
|
|
if (contains_player_start)
|
|
{
|
|
SCP_string issue_buf;
|
|
sprintf(issue_buf, "Potential issue detected in wing %s:\n\nThis wing contains a player start and a custom arrival cue, but only one wave. The arrival cue must evaluate to true at mission start, or the player will not be created.", Wings[i].name);
|
|
if (Fred_main_wnd->MessageBox(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<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (TVT_wings[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<MAX_STARTING_WINGS; i++)
|
|
{
|
|
if (Starting_wings[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<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (TVT_wings[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<MAX_STARTING_WINGS; i++)
|
|
{
|
|
if (Starting_wings[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<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (TVT_wings[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<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (TVT_wings[i] >= 0)
|
|
{
|
|
if (global_error_check_mixed_player_wing(TVT_wings[i]))
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i<MAX_STARTING_WINGS; i++)
|
|
{
|
|
if (Starting_wings[i] >= 0)
|
|
{
|
|
if (global_error_check_mixed_player_wing(Starting_wings[i]))
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0; i<MAX_STARTING_WINGS; i++)
|
|
{
|
|
starting_wing_count[i] = 0;
|
|
|
|
if (i < MAX_STARTING_WINGS - 1)
|
|
{
|
|
starting_wing_list += Starting_wing_names[i];
|
|
if (MAX_STARTING_WINGS > 2)
|
|
starting_wing_list += ",";
|
|
starting_wing_list += " ";
|
|
}
|
|
else
|
|
{
|
|
starting_wing_list += "or ";
|
|
starting_wing_list += Starting_wing_names[i];
|
|
}
|
|
}
|
|
for (i=0; i<MAX_TVT_WINGS; i++)
|
|
{
|
|
tvt_wing_count[i] = 0;
|
|
|
|
if (i < MAX_TVT_WINGS - 1)
|
|
{
|
|
tvt_wing_list += TVT_wing_names[i];
|
|
if (MAX_TVT_WINGS > 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<MAX_STARTING_WINGS; i++)
|
|
{
|
|
if (Starting_wings[i] == z)
|
|
{
|
|
in_starting_wing = 1;
|
|
starting_wing_count[i]++;
|
|
}
|
|
}
|
|
for (i=0; i<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (TVT_wings[i] == z)
|
|
{
|
|
in_tvt_wing = 1;
|
|
tvt_wing_count[i]++;
|
|
}
|
|
}
|
|
|
|
// make sure the player belongs to his proper wing
|
|
if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
|
|
{
|
|
if (!in_tvt_wing)
|
|
{
|
|
err = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!in_starting_wing)
|
|
{
|
|
err = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
|
|
{
|
|
if (error("Player %s should be part of %s wing", Ships[ship_instance].ship_name, static_cast<LPCTSTR>(tvt_wing_list)))
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (error("Player %s should be part of %s wing", Ships[ship_instance].ship_name, static_cast<LPCTSTR>(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<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (!tvt_wing_count[i])
|
|
{
|
|
if (error("%s wing doesn't contain any players (which it should)", TVT_wing_names[i]))
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CFREDView::error(const char *msg, ...)
|
|
{
|
|
char buf[2048];
|
|
va_list args;
|
|
|
|
va_start(args, msg);
|
|
vsnprintf(buf, sizeof(buf)-1, msg, args);
|
|
va_end(args);
|
|
buf[sizeof(buf)-1] = '\0';
|
|
|
|
g_err = 1;
|
|
if (MessageBox(buf, "Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CFREDView::internal_error(const char *msg, ...)
|
|
{
|
|
SCP_string buf;
|
|
va_list args;
|
|
|
|
va_start(args, msg);
|
|
vsprintf(buf, msg, args);
|
|
va_end(args);
|
|
|
|
g_err = 1;
|
|
|
|
#ifndef NDEBUG
|
|
buf += "\n\nThis is an internal error. Please notify a coder about this. Click cancel to debug.";
|
|
|
|
if (MessageBox(buf.c_str(), "Internal Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
|
|
Int3(); // drop to debugger so the problem can be analyzed.
|
|
#else
|
|
MessageBox(buf.c_str(), "Error", MB_OK | MB_ICONEXCLAMATION);
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
int CFREDView::fred_check_sexp(int sexp, int type, const char *location, ...)
|
|
{
|
|
SCP_string location_buf, sexp_buf, error_buf, bad_node_str, issue_msg;
|
|
int err = 0, z, faulty_node;
|
|
va_list args;
|
|
|
|
va_start(args, location);
|
|
vsprintf(location_buf, location, args);
|
|
va_end(args);
|
|
|
|
if (sexp == -1)
|
|
return 0;
|
|
|
|
z = check_sexp_syntax(sexp, type, 1, &faulty_node);
|
|
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, "Error in %s: %s\n\n%s\n\n(Bad node appears to be: %s)", location_buf.c_str(), sexp_error_message(z), sexp_buf.c_str(), bad_node_str.c_str());
|
|
|
|
if (z < 0 && z > -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; i<MAX_AI_GOALS; i++)
|
|
if (!ai_query_goal_valid(ship, goals[i].ai_mode)) {
|
|
if (Fred_view_wnd->error("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; j<Wings[wing].wave_count; j++)
|
|
for (i=0; i<MAX_AI_GOALS; i++)
|
|
if (!ai_query_goal_valid(Wings[wing].ship_index[j], goals[i].ai_mode)) {
|
|
if (Fred_view_wnd->error("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<MAX_AI_GOALS; i++) {
|
|
switch (goals[i].ai_mode) {
|
|
case AI_GOAL_NONE:
|
|
case AI_GOAL_CHASE_ANY:
|
|
case AI_GOAL_CHASE_SHIP_CLASS:
|
|
case AI_GOAL_CHASE_SHIP_TYPE:
|
|
case AI_GOAL_UNDOCK:
|
|
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
|
case AI_GOAL_PLAY_DEAD:
|
|
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
|
case AI_GOAL_WARP:
|
|
flag = 0;
|
|
break;
|
|
|
|
case AI_GOAL_WAYPOINTS:
|
|
case AI_GOAL_WAYPOINTS_ONCE:
|
|
flag = 1;
|
|
break;
|
|
|
|
case AI_GOAL_DOCK:
|
|
if (ship < 0)
|
|
return "Wings can't dock";
|
|
FALLTHROUGH;
|
|
|
|
case AI_GOAL_DESTROY_SUBSYSTEM:
|
|
case AI_GOAL_CHASE:
|
|
case AI_GOAL_GUARD:
|
|
case AI_GOAL_DISARM_SHIP:
|
|
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
|
case AI_GOAL_DISABLE_SHIP:
|
|
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
|
case AI_GOAL_EVADE_SHIP:
|
|
case AI_GOAL_STAY_NEAR_SHIP:
|
|
case AI_GOAL_FORM_ON_WING:
|
|
case AI_GOAL_IGNORE:
|
|
case AI_GOAL_IGNORE_NEW:
|
|
flag = 2;
|
|
break;
|
|
|
|
case AI_GOAL_CHASE_WING:
|
|
case AI_GOAL_GUARD_WING:
|
|
flag = 3;
|
|
break;
|
|
|
|
case AI_GOAL_STAY_STILL:
|
|
flag = 4;
|
|
break;
|
|
|
|
default:
|
|
return "*Invalid goal type";
|
|
}
|
|
|
|
found = 0;
|
|
if (flag > 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; j++)
|
|
if (Wings[j].wave_count && !stricmp(Wings[j].name, goals[i].target_name))
|
|
break;
|
|
|
|
if (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<num; j++) {
|
|
Assert(Docking_bay_list[j]);
|
|
if (!stricmp(goals[i].docker.name, Docking_bay_list[j])) {
|
|
dock1 = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
model2 = Ship_info[Ships[inst].ship_info_index].model_num;
|
|
num = get_docking_list(model2);
|
|
for (j=0; j<num; j++) {
|
|
Assert(Docking_bay_list[j]);
|
|
if (!stricmp(goals[i].dockee.name, Docking_bay_list[j])) {
|
|
dock2 = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dock1 < 0)
|
|
return "Invalid docker point";
|
|
|
|
if (dock2 < 0)
|
|
return "Invalid dockee point";
|
|
|
|
if ((dock1 >= 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, "<Any wingman>") || !stricmp(who_from, "<Any allied>") || (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<SCP_string> 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<char[]> 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; i<MAX_SHIPS; i++)
|
|
Ships[i].group &= ~n;
|
|
|
|
objp = GET_FIRST(&obj_used_list);
|
|
while (objp != END_OF_LIST(&obj_used_list)) {
|
|
if (objp->flags[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<Wings[wing].wave_count; i++)
|
|
mark_object(wing_objects[wing][i]);
|
|
|
|
Assert(Wings[wing].special_ship >= 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<os::GraphicsOperations> 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);
|
|
}
|