2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Fred2/FREDView.cpp $
15 * View class for a document/view architechure design program, which we don't
16 * want or need, but MFC forces us to use. This is the main place we handle
17 * MFC messages, events, etc. Sort of the interface between our code and MFC.
18 * There is also a lot of our code in here related to these things.
21 * Revision 1.3 2002/06/09 04:41:16 relnev
22 * added copyright header
24 * Revision 1.2 2002/05/07 03:16:44 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:08 root
31 * 17 7/15/99 3:07p Dave
32 * 32 bit detection support. Mouse coord commandline.
34 * 16 7/09/99 5:54p Dave
35 * Seperated cruiser types into individual types. Added tons of new
36 * briefing icons. Campaign screen.
38 * 15 6/04/99 2:20p Andsager
39 * Add dump stats basic functionality
41 * 14 4/07/99 6:21p Dave
42 * Fred and Freespace support for multiple background bitmaps and suns.
43 * Fixed link errors on all subprojects. Moved encrypt_init() to
44 * cfile_init() and lcl_init(), since its safe to call twice.
46 * 13 3/26/99 4:49p Dave
47 * Made cruisers able to dock with stuff. Made docking points and paths
50 * 12 3/20/99 5:09p Dave
51 * Fixed release build fred warnings and unhandled exception.
53 * 11 3/04/99 11:56a Johnson
54 * Fixed an undo-rotation bug.
56 * 10 3/02/99 9:25p Dave
57 * Added a bunch of model rendering debug code. Started work on fixing
58 * beam weapon wacky firing.
60 * 9 3/01/99 10:00a Dave
61 * Fxied several dogfight related stats bugs.
63 * 8 2/23/99 2:32p Dave
64 * First run of oldschool dogfight mode.
66 * 7 1/27/99 4:09p Andsager
67 * Added highlight to ship subsystems
69 * 6 1/07/99 1:52p Andsager
70 * Initial check in of Sexp_variables
72 * 5 12/18/98 1:49a Dave
73 * Fixed Fred initialization problem resulting from hi-res mode changes.
75 * 4 10/13/98 9:27a Dave
76 * Started neatening up freespace.h
78 * 3 10/12/98 1:01p Dave
79 * Fixed object rotation bug (uninitialized data). Changed a few stubs to
80 * correspond to new var names.
82 * 2 10/07/98 6:28p Dave
83 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
84 * Fred. Globalized mission and campaign file extensions. Removed Silent
85 * Threat specific code.
87 * 1 10/07/98 3:00p Dave
89 * 248 9/16/98 6:54p Dave
90 * Upped max sexpression nodes to 1800 (from 1600). Changed FRED to sort
91 * the ship list box. Added code so that tracker stats are not stored with
94 * 247 9/14/98 3:40p Allender
95 * better error checking for invalid number of waves for player wings in a
96 * multiplayer game. Better popup message in FreeSpace side.
98 * 246 6/18/98 4:28p Hoffoss
99 * Made invalid dock points in an initial order flag an error in Fred.
101 * 245 6/17/98 4:50p Hoffoss
102 * Added error checking for arrival delays used on wing player is in.
104 * 244 6/16/98 10:24a Hoffoss
105 * Switched internal errors over to normal looking errors for release
108 * 243 5/21/98 11:48a Hoffoss
109 * Removed check in and check out options.
111 * 242 5/21/98 12:58a Hoffoss
112 * Fixed warnings optimized build turned up.
114 * 241 5/19/98 1:19p Allender
115 * new low level reliable socket reading code. Make all missions/campaign
116 * load/save to data missions folder (i.e. we are rid of the player
119 * 240 5/14/98 5:31p Hoffoss
120 * Added some more error checking.
122 * 239 5/10/98 10:05p Allender
123 * only show cutscenes which have been seen before. Made Fred able to
124 * write missions anywhere, defaulting to player misison folder, not data
125 * mission folder. Fix FreeSpace code to properly read missions from
128 * 238 4/28/98 2:13p Hoffoss
129 * Added code to help keep invalid player ship types from existing in
132 * 237 4/26/98 6:05p Hoffoss
133 * Added multiplayer error checks requested by Dave B.
135 * 236 4/17/98 2:37p Duncan
136 * Added check to error checker for arrival/depature targets valid.
138 * 235 4/14/98 4:35p Hoffoss
139 * Fixed bug with launching FreeSpace from Fred. Current working
140 * directory wasn't being set properly.
142 * 234 4/14/98 3:38p Hoffoss
143 * Fixed the FreeSpace launch code in Fred.
145 * 233 4/07/98 9:42a Allender
146 * put in persona combo box into ship editor. Removed code to assign
147 * personas based on message
149 * 232 4/01/98 10:48a Hoffoss
150 * Changed Fred to not allow command briefings in multiplayer missions.
152 * 231 3/26/98 3:01p Hoffoss
153 * Put in check for alpha wing num ships < 4 for furball multiplayer
156 * 230 3/25/98 4:14p Hoffoss
157 * Split ship editor up into ship editor and a misc dialog, which tracks
160 * 229 3/23/98 4:04p Hoffoss
161 * Fixed dialog window initialization so it looks better at startup (they
162 * don't flash on for a second).
164 * 228 3/21/98 7:36p Lawrance
165 * Move jump nodes to own lib.
167 * 227 3/19/98 3:37p Adam
168 * Fixed Int3() when you try to right click on a briefing icon.
170 * 226 3/16/98 5:05p Hoffoss
171 * Fixed viewpoint bug.
173 * 225 3/12/98 2:21p Johnson
174 * Fixed some Fred bugs related to jump nodes.
176 * 224 3/10/98 6:11p Hoffoss
177 * Added jump node renaming abilities to Fred.
179 * 223 3/10/98 4:26p Hoffoss
180 * Changed jump node structure to include a name. Position is now taken
181 * from the object (each jump node has an associated object now).
183 * 222 3/09/98 10:03p Hoffoss
184 * Added support for loading/saving jump nodes to mission files.
186 * 221 3/09/98 10:56a Hoffoss
187 * Added jump node objects to Fred.
189 * 220 3/05/98 3:59p Hoffoss
190 * Added a bunch of new command brief stuff, and asteroid initialization
193 * 219 2/26/98 4:59p Allender
194 * groundwork for team vs team briefings. Moved weaponry pool into the
195 * Team_data structure. Added team field into the p_info structure.
196 * Allow for mutliple structures in the briefing code.
198 * 218 2/09/98 9:25p Allender
199 * team v team support. multiple pools and breifings
201 * 217 2/07/98 9:13p Hoffoss
202 * Added some more error checking to global error checker.
204 * 216 2/06/98 4:39p Hoffoss
205 * Added better checking for whether Fred is in the foreground or
208 * 215 2/04/98 4:32p Allender
209 * support for multiple briefings and debriefings. Changes to mission
210 * type (now a bitfield). Bitfield defs for multiplayer modes
212 * 214 2/02/98 4:36p Hoffoss
213 * Made no mission title given flag an error.
215 * 213 1/29/98 5:14p Hoffoss
216 * Added error checking for more than 4 ships in a player starting wing.
218 * 212 1/21/98 5:22p Hoffoss
219 * Added check to global error checker to make sure Alpha wing exists for
220 * multiplayer missions.
222 * 211 1/14/98 8:40p Allender
223 * don't check builtin messages when checking persona stuff
225 * 210 1/07/98 11:24p Allender
226 * add latency of 0 to key_mark function calls
228 * 209 12/31/97 3:56p Hoffoss
229 * Forced alpha wing to always have a true arrival cue.
231 * 208 12/09/97 8:11a Allender
232 * have Fred warn on certain starting wing conditions
234 * 207 11/24/97 10:14p Allender
235 * removed num_ships from use!!!! it was creating problems
237 * 206 11/24/97 11:07a Allender
238 * error checking on wings ignoring player orders
240 * 205 11/17/97 4:57p Allender
241 * added persona support in FreeSpace. A couple of new messages for
242 * message.tbl which Dan didn't have
244 * 204 11/14/97 5:21p Johnson
245 * Added debriefing formulas to error checker.
247 * 203 11/05/97 4:43p Allender
248 * reworked medal/rank system to read all data from tables. Made Fred
249 * read medals.tbl. Changed ai-warp to ai-warp-out which doesn't require
250 * waypoint for activation
252 * 202 10/30/97 3:30p Hoffoss
253 * Made anti-aliased gridlines an option in Fred.
255 * 201 10/28/97 9:54a Jasen
256 * don't check for personas when wing is sending message
258 * 200 10/22/97 3:15p Hoffoss
259 * Fixed ai-stay-still initial order to use waypoints instead of waypoint
262 * 199 10/22/97 1:58p Hoffoss
263 * Added support for AI_GOALS_PLAY_DEAD and changed AI_GOALS_STAY_STILL
266 * 198 10/14/97 10:59a Allender
267 * more persona work. Made global error checker call funciton to assign
270 * 197 10/10/97 5:03p Allender
271 * started work on ai-stay-still
273 * 196 10/01/97 12:37p Hoffoss
274 * Changed Fred (and FreeSpace) to utilize alpha, beta and gamma as player
275 * starting wing names.
277 * 195 9/16/97 9:41p Hoffoss
278 * Changed Fred code around to stop using Parse_player structure for
279 * player information, and use actual ships instead.
281 * 194 9/10/97 3:48p Duncan
282 * Added a case that was never added in the past (probably overlooked).
284 * 193 9/09/97 3:39p Sandeep
285 * warning level 4 bugs
287 * 192 9/09/97 2:12p Hoffoss
288 * Added code to allow briefing editor view to be a 1:1 pixel size fixed
289 * as the FreeSpace view will have.
291 * 191 9/06/97 2:13p Mike
292 * Replace support for TEAM_NEUTRAL
294 * 190 9/03/97 4:32p Hoffoss
295 * Added error number range error checking to Fred, and defaulted numbers
296 * for # of times docked to 1 in sexp trees.
298 * 189 9/02/97 4:32p Hoffoss
299 * Made minimized child windows restore if the window is activated.
301 * 188 9/02/97 1:34p Johnson
302 * Fixed bug I swear wasn't there when I checked this in originally.
305 * 187 9/01/97 6:59p Hoffoss
306 * Added source safe checkin and checkout capabilities to Fred.
308 * 186 8/28/97 8:56a Hoffoss
309 * Added more checking to sexp error checker, fixed some bugs.
311 * 185 8/26/97 4:18p Hoffoss
312 * Added error checking to initial orders dialog when ok is clicked.
314 * 184 8/25/97 5:58p Hoffoss
315 * Created menu items for keypress functions in Fred, and fixed bug this
316 * uncovered with wing_delete function.
318 * 183 8/22/97 4:16p Hoffoss
319 * added support for arrival and departure info in ship editor using
320 * wing's info if editing marked ships in a wing instead of using ship's.
322 * 182 8/18/97 9:31p Hoffoss
323 * Added grid adjustment dialog and shield system editor dialog.
325 * 181 8/17/97 10:22p Hoffoss
326 * Fixed several bugs in Fred with Undo feature. In the process, recoded
327 * a lot of CFile.cpp.
329 * 180 8/16/97 5:23p Hoffoss
330 * Added restrictions for single player mission type to allow only 1
333 * 179 8/16/97 2:02a Hoffoss
334 * Made docked objects move together in Fred.
336 * 178 8/15/97 11:08a Hoffoss
337 * Created a list of order types that can be used for several things, and
338 * yet easily changable. Added order error checking against ship types.
340 * 177 8/15/97 1:07a Hoffoss
341 * Changed code to disallow some ship types from being in a wing, and
342 * disallowing some ship types from being able to have initial orders.
344 * 176 8/14/97 6:37p Hoffoss
345 * Added briefing icon id support to Fred.
347 * 175 8/14/97 2:32p Hoffoss
348 * fixed bug where controlling an object doesn't cause screen updates, and
349 * added a number of cool features to viewpoint/control object code.
351 * 174 8/14/97 9:30a Hoffoss
352 * Added support for new ai goals "stay near ship" and "keep safe
355 * 173 8/13/97 6:23p Hoffoss
356 * Fixed initially docked code in Fred.
358 * 172 8/13/97 5:40p Hoffoss
361 * 171 8/12/97 10:42p Hoffoss
362 * Changed code to campaign editor load an accelerator table when created.
364 * 170 8/12/97 6:32p Hoffoss
365 * Added code to allow hiding of arrival and departure cues in editors.
367 * 169 8/12/97 5:56p Johnson
368 * Fixed bug with global error checker. Initially docked ships flagged as
369 * error when they aren't really.
371 * 168 8/12/97 1:29p Duncan
372 * Fixed bug with ai_undock initial order.
374 * 167 8/11/97 7:11p Hoffoss
375 * Somehow SS didn't merge the files, so I've reconstructed the changes
378 * 166 8/11/97 6:54p Hoffoss
379 * Groups now supported in Fred.
381 * 165 8/11/97 11:51a Allender
382 * added stamp stuff to Fred
384 * 164 8/07/97 6:01p Hoffoss
385 * Added a rotate about selected object button to toolbar and
386 * functionality, as requested by Comet.
388 * 163 8/07/97 2:07p Hoffoss
389 * Added duplicate icon label error checking to global error checker, and
390 * made briefign mode boxmark only icons if at least one icon is in the
393 * 162 8/06/97 10:20a Hoffoss
394 * Changed rotation speeds to be less linear and hopefully more useful.
396 * 161 8/05/97 2:27p Jasen
397 * Fixed bug in global error checker that caused crashes when in briefing
400 * 160 8/05/97 1:31p Hoffoss
401 * Removed excessive source control info from header.
403 * 159 8/01/97 5:52p Hoffoss
404 * Changed initially docked to disallow illegal docking combinations, and
405 * changed error checker to check for this as well.
407 * 158 8/01/97 3:10p Hoffoss
408 * Made Sexp help hidable.
410 * 157 8/01/97 12:52p Hoffoss
411 * Added variable, fixed bug with global error check.
413 * 156 7/31/97 6:41p Hoffoss
414 * Added checks to global error checker.
416 * 155 7/30/97 4:30p Hoffoss
417 * Made Fred sexp error checker more explicit.
419 * 154 7/29/97 5:16p Hoffoss
420 * Fixed bug in ship_query_general_type() and added docking checking to
421 * Fred's error checking.
423 * 153 7/29/97 1:44p Hoffoss
424 * Make player ships exception to ship target within same wing error
434 #include "fredview.h"
435 #include "fredrender.h"
440 #include "management.h"
444 #include "linklist.h"
445 #include "fvi.h" // For find_plane_line_intersection
451 #include "ship.h" // for ship names
452 #include "missiongoalsdlg.h"
454 #include "ship_select.h"
455 #include "playerstarteditor.h"
456 #include "orienteditor.h"
457 #include "eventeditor.h"
458 #include "messageeditordlg.h"
459 #include "starfield.h"
460 #include "starfieldeditor.h"
461 #include "floating.h"
462 #include "reinforcementeditordlg.h"
463 #include "asteroideditordlg.h"
464 #include "campaigntreewnd.h"
465 #include "debriefingeditordlg.h"
466 #include "adjustgriddlg.h"
467 #include "shieldsysdlg.h"
468 #include "cmdbrief.h"
469 #include "jumpnode.h"
470 #include "dumpstats.h"
473 #define new DEBUG_NEW
475 static char THIS_FILE[] = __FILE__;
478 subsys_to_render Render_subsys;
480 // the next variable is used for executable stamping -- please leave it alone!!!
481 #define FRED_EXPIRE_TIME (7 * 1000)
482 char stamp[STAMP_STRING_LENGTH] = { STAMP_STRING };
485 #define EXPIRE_BAD_CHECKSUM 1
486 #define EXPIRE_BAD_TIME 2
488 #define SHIP_TYPES 8000
489 #define REDUCER 100.0f
490 #define DUP_DRAG_OF_WING 2
492 LOCAL int Duped_wing;
494 int Autosave_disabled = 0;
495 int Show_sexp_help = 1;
498 int Show_friendly = 1;
499 int Show_hostile = 1;
500 int Show_neutral = 1;
501 int Show_ship_info = 1;
502 int Show_ship_models = 0;
503 int Show_compass = 1;
504 int Show_dock_points = 0;
505 int Show_paths_fred = 0;
506 int Selection_lock = 0;
510 int Marked = 0, moved = 0;
512 int Cursor_over = -1;
514 int physics_speed = 1;
515 int physics_rot = 20;
517 int last_mouse_x, last_mouse_y, mouse_dx, mouse_dy;
519 int Id_select_type_jump_node;
520 int Id_select_type_start = 0;
521 int Id_select_type_waypoint = 0;
522 int Hide_ship_cues = 0, Hide_wing_cues = 0;
523 vector original_pos, saved_cam_pos;
524 matrix bitmap_matrix_backup, saved_cam_orient = { 0.0f };
525 Marking_box marking_box;
526 object_orient_pos rotation_backup[MAX_OBJECTS];
528 // used by error checker, but needed in more than just one function.
529 char *names[MAX_OBJECTS], flags[MAX_OBJECTS];
533 void view_universe(int just_marked = 0);
534 void select_objects();
535 void drag_rotate_save_backup();
537 /////////////////////////////////////////////////////////////////////////////
540 CFREDView *Fred_view_wnd = NULL;
542 IMPLEMENT_DYNCREATE(CFREDView, CView)
544 BEGIN_MESSAGE_MAP(CFREDView, CView)
545 ON_MESSAGE(WM_GOODBYE, OnGoodbye)
546 ON_MESSAGE(WM_MENU_POPUP_SHIPS, OnMenuPopupShips)
547 ON_MESSAGE(WM_MENU_POPUP_EDIT, OnMenuPopupEdit)
549 //{{AFX_MSG_MAP(CFREDView)
550 ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
551 ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
552 ON_COMMAND(ID_SHOW_WAYPOINTS, OnViewWaypoints)
553 ON_UPDATE_COMMAND_UI(ID_SHOW_WAYPOINTS, OnUpdateViewWaypoints)
555 ON_COMMAND(ID_EDITORS_SHIPS, OnEditorsShips)
563 ON_COMMAND(ID_MISCSTUFF_SHOWSHIPSASICONS, OnMiscstuffShowshipsasicons)
565 ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnEditPopupShowShipIcons)
566 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnUpdateEditPopupShowShipIcons)
567 ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnEditPopupShowShipModels)
568 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnUpdateEditPopupShowShipModels)
570 ON_COMMAND(ID_SHOW_PATHS, OnShowPaths)
571 ON_UPDATE_COMMAND_UI(ID_SHOW_PATHS, OnUpdateShowPaths)
572 ON_COMMAND(ID_SHOW_DOCK_POINTS, OnShowDockPoints)
573 ON_UPDATE_COMMAND_UI(ID_SHOW_DOCK_POINTS, OnUpdateShowDockPoints)
575 ON_COMMAND(ID_MISC_STATISTICS, OnMiscStatistics)
576 ON_COMMAND(ID_EDIT_POPUP_SHOW_COMPASS, OnEditPopupShowCompass)
577 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_COMPASS, OnUpdateEditPopupShowCompass)
578 ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_EXTERNAL, OnUpdateChangeViewpointExternal)
579 ON_COMMAND(ID_CHANGE_VIEWPOINT_EXTERNAL, OnChangeViewpointExternal)
580 ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_FOLLOW, OnUpdateChangeViewpointFollow)
581 ON_COMMAND(ID_CHANGE_VIEWPOINT_FOLLOW, OnChangeViewpointFollow)
582 ON_COMMAND(ID_EDITORS_GOALS, OnEditorsGoals)
583 ON_COMMAND(ID_SPEED1, OnSpeed1)
584 ON_COMMAND(ID_SPEED2, OnSpeed2)
585 ON_COMMAND(ID_SPEED5, OnSpeed5)
586 ON_COMMAND(ID_SPEED10, OnSpeed10)
587 ON_UPDATE_COMMAND_UI(ID_SPEED1, OnUpdateSpeed1)
588 ON_COMMAND(ID_SPEED3, OnSpeed3)
589 ON_COMMAND(ID_SPEED8, OnSpeed8)
590 ON_COMMAND(ID_ROT1, OnRot1)
591 ON_COMMAND(ID_ROT2, OnRot2)
592 ON_COMMAND(ID_ROT3, OnRot3)
593 ON_COMMAND(ID_ROT4, OnRot4)
594 ON_COMMAND(ID_ROT5, OnRot5)
595 ON_UPDATE_COMMAND_UI(ID_SPEED2, OnUpdateSpeed2)
596 ON_UPDATE_COMMAND_UI(ID_SPEED3, OnUpdateSpeed3)
597 ON_UPDATE_COMMAND_UI(ID_SPEED5, OnUpdateSpeed5)
598 ON_UPDATE_COMMAND_UI(ID_SPEED8, OnUpdateSpeed8)
599 ON_UPDATE_COMMAND_UI(ID_SPEED10, OnUpdateSpeed10)
600 ON_UPDATE_COMMAND_UI(ID_ROT1, OnUpdateRot1)
601 ON_UPDATE_COMMAND_UI(ID_ROT2, OnUpdateRot2)
602 ON_UPDATE_COMMAND_UI(ID_ROT3, OnUpdateRot3)
603 ON_UPDATE_COMMAND_UI(ID_ROT4, OnUpdateRot4)
604 ON_UPDATE_COMMAND_UI(ID_ROT5, OnUpdateRot5)
605 ON_COMMAND(ID_CONTROL_MODE_CAMERA, OnControlModeCamera)
606 ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_CAMERA, OnUpdateControlModeCamera)
607 ON_COMMAND(ID_CONTROL_MODE_SHIP, OnControlModeShip)
608 ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_SHIP, OnUpdateControlModeShip)
609 ON_COMMAND(ID_SHOW_GRID_POSITIONS, OnShowGridPositions)
610 ON_UPDATE_COMMAND_UI(ID_SHOW_GRID_POSITIONS, OnUpdateShowGridPositions)
611 ON_COMMAND(ID_SHOW_COORDINATES, OnShowCoordinates)
612 ON_UPDATE_COMMAND_UI(ID_SHOW_COORDINATES, OnUpdateShowCoordinates)
613 ON_COMMAND(ID_SPEED50, OnSpeed50)
614 ON_UPDATE_COMMAND_UI(ID_SPEED50, OnUpdateSpeed50)
615 ON_COMMAND(ID_SPEED100, OnSpeed100)
616 ON_UPDATE_COMMAND_UI(ID_SPEED100, OnUpdateSpeed100)
617 ON_COMMAND(ID_SELECT, OnSelect)
618 ON_UPDATE_COMMAND_UI(ID_SELECT, OnUpdateSelect)
619 ON_COMMAND(ID_SELECT_AND_MOVE, OnSelectAndMove)
620 ON_UPDATE_COMMAND_UI(ID_SELECT_AND_MOVE, OnUpdateSelectAndMove)
621 ON_COMMAND(ID_SELECT_AND_ROTATE, OnSelectAndRotate)
622 ON_UPDATE_COMMAND_UI(ID_SELECT_AND_ROTATE, OnUpdateSelectAndRotate)
623 ON_COMMAND(ID_CONSTRAIN_X, OnConstrainX)
624 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_X, OnUpdateConstrainX)
625 ON_COMMAND(ID_CONSTRAIN_Y, OnConstrainY)
626 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Y, OnUpdateConstrainY)
627 ON_COMMAND(ID_CONSTRAIN_Z, OnConstrainZ)
628 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Z, OnUpdateConstrainZ)
629 ON_COMMAND(ID_CONSTRAIN_XZ, OnConstrainXz)
630 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XZ, OnUpdateConstrainXz)
631 ON_COMMAND(ID_SELECTION_LOCK, OnSelectionLock)
632 ON_UPDATE_COMMAND_UI(ID_SELECTION_LOCK, OnUpdateSelectionLock)
633 ON_WM_LBUTTONDBLCLK()
634 ON_COMMAND(ID_DOUBLE_FINE_GRIDLINES, OnDoubleFineGridlines)
635 ON_UPDATE_COMMAND_UI(ID_DOUBLE_FINE_GRIDLINES, OnUpdateDoubleFineGridlines)
636 ON_COMMAND(ID_SHOW_DISTANCES, OnShowDistances)
637 ON_UPDATE_COMMAND_UI(ID_SHOW_DISTANCES, OnUpdateShowDistances)
638 ON_COMMAND(ID_UNIVERSAL_HEADING, OnUniversalHeading)
639 ON_UPDATE_COMMAND_UI(ID_UNIVERSAL_HEADING, OnUpdateUniversalHeading)
640 ON_COMMAND(ID_FLYING_CONTROLS, OnFlyingControls)
641 ON_UPDATE_COMMAND_UI(ID_FLYING_CONTROLS, OnUpdateFlyingControls)
642 ON_COMMAND(ID_ROTATE_LOCALLY, OnRotateLocally)
643 ON_UPDATE_COMMAND_UI(ID_ROTATE_LOCALLY, OnUpdateRotateLocally)
644 ON_COMMAND(ID_CONSTRAIN_XY, OnConstrainXy)
645 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XY, OnUpdateConstrainXy)
646 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_YZ, OnUpdateConstrainYz)
647 ON_COMMAND(ID_CONSTRAIN_YZ, OnConstrainYz)
648 ON_COMMAND(ID_SELECT_LIST, OnSelectList)
649 ON_COMMAND(ID_ZOOM_EXTENTS, OnZoomExtents)
650 ON_COMMAND(ID_ZOOM_SELECTED, OnZoomSelected)
651 ON_UPDATE_COMMAND_UI(ID_ZOOM_SELECTED, OnUpdateZoomSelected)
652 ON_COMMAND(ID_FORM_WING, OnFormWing)
653 ON_UPDATE_COMMAND_UI(ID_FORM_WING, OnUpdateFormWing)
654 ON_COMMAND(ID_DISBAND_WING, OnDisbandWing)
655 ON_UPDATE_COMMAND_UI(ID_DISBAND_WING, OnUpdateDisbandWing)
656 ON_COMMAND(ID_SHOW_HORIZON, OnShowHorizon)
657 ON_UPDATE_COMMAND_UI(ID_SHOW_HORIZON, OnUpdateShowHorizon)
658 ON_COMMAND(ID_EDITORS_WING, OnEditorsWing)
659 ON_COMMAND(ID_EDITORS_PLAYER, OnEditorsPlayer)
660 ON_COMMAND(ID_EDITORS_ORIENT, OnEditorsOrient)
661 ON_COMMAND(ID_EDITORS_EVENTS, OnEditorsEvents)
662 ON_UPDATE_COMMAND_UI(ID_EDITORS_ORIENT, OnUpdateEditorsOrient)
663 ON_COMMAND(ID_EDITORS_MESSAGE, OnEditorsMessage)
664 ON_COMMAND(ID_EDITORS_STARFIELD, OnEditorsStarfield)
665 ON_COMMAND(ID_EDITORS_BG_BITMAPS, OnEditorsBgBitmaps)
666 ON_COMMAND(ID_EDITORS_REINFORCEMENT, OnEditorsReinforcement)
667 ON_COMMAND(ID_ERROR_CHECKER, OnErrorChecker)
668 ON_COMMAND(ID_EDITORS_WAYPOINT, OnEditorsWaypoint)
669 ON_COMMAND(ID_VIEW_OUTLINES, OnViewOutlines)
670 ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINES, OnUpdateViewOutlines)
671 ON_UPDATE_COMMAND_UI(ID_NEW_SHIP_TYPE, OnUpdateNewShipType)
672 ON_COMMAND(ID_SHOW_STARFIELD, OnShowStarfield)
673 ON_UPDATE_COMMAND_UI(ID_SHOW_STARFIELD, OnUpdateShowStarfield)
674 ON_COMMAND(ID_ASTEROID_EDITOR, OnAsteroidEditor)
675 ON_COMMAND(ID_RUN_FREESPACE, OnRunFreespace)
676 ON_COMMAND(ID_EDITOR_CAMPAIGN, OnEditorCampaign)
677 ON_COMMAND(ID_SHOW_SHIPS, OnShowShips)
678 ON_UPDATE_COMMAND_UI(ID_SHOW_SHIPS, OnUpdateShowShips)
679 ON_COMMAND(ID_SHOW_STARTS, OnShowStarts)
680 ON_UPDATE_COMMAND_UI(ID_SHOW_STARTS, OnUpdateShowStarts)
681 ON_COMMAND(ID_SHOW_FRIENDLY, OnShowFriendly)
682 ON_UPDATE_COMMAND_UI(ID_SHOW_FRIENDLY, OnUpdateShowFriendly)
683 ON_COMMAND(ID_SHOW_HOSTILE, OnShowHostile)
684 ON_UPDATE_COMMAND_UI(ID_SHOW_HOSTILE, OnUpdateShowHostile)
685 ON_COMMAND(ID_TOGGLE_VIEWPOINT, OnToggleViewpoint)
686 ON_COMMAND(ID_REVERT, OnRevert)
687 ON_UPDATE_COMMAND_UI(ID_REVERT, OnUpdateRevert)
689 ON_COMMAND(ID_HIDE_OBJECTS, OnHideObjects)
690 ON_COMMAND(ID_SHOW_HIDDEN_OBJECTS, OnShowHiddenObjects)
691 ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
692 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
693 ON_COMMAND(ID_EDITORS_BRIEFING, OnEditorsBriefing)
694 ON_COMMAND(ID_EDITORS_DEBRIEFING, OnEditorsDebriefing)
695 ON_COMMAND(ID_SAVE_CAMERA, OnSaveCamera)
696 ON_COMMAND(ID_RESTORE_CAMERA, OnRestoreCamera)
697 ON_UPDATE_COMMAND_UI(ID_RESTORE_CAMERA, OnUpdateRestoreCamera)
698 ON_COMMAND(ID_SHOW_SEXP_HELP, OnShowSexpHelp)
699 ON_UPDATE_COMMAND_UI(ID_SHOW_SEXP_HELP, OnUpdateShowSexpHelp)
700 ON_COMMAND(ID_LOOKAT_OBJ, OnLookatObj)
701 ON_UPDATE_COMMAND_UI(ID_LOOKAT_OBJ, OnUpdateLookatObj)
702 ON_COMMAND(ID_EDITORS_ADJUST_GRID, OnEditorsAdjustGrid)
703 ON_COMMAND(ID_EDITORS_SHIELD_SYS, OnEditorsShieldSys)
704 ON_COMMAND(ID_LEVEL_OBJ, OnLevelObj)
705 ON_COMMAND(ID_ALIGN_OBJ, OnAlignObj)
706 ON_COMMAND(ID_CONTROL_OBJ, OnControlObj)
707 ON_COMMAND(ID_NEXT_OBJ, OnNextObj)
708 ON_COMMAND(ID_PREV_OBJ, OnPrevObj)
709 ON_COMMAND(ID_EDIT_DELETE_WING, OnEditDeleteWing)
710 ON_COMMAND(ID_MARK_WING, OnMarkWing)
711 ON_UPDATE_COMMAND_UI(ID_CONTROL_OBJ, OnUpdateControlObj)
712 ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
713 ON_COMMAND(ID_AA_GRIDLINES, OnAaGridlines)
714 ON_UPDATE_COMMAND_UI(ID_AA_GRIDLINES, OnUpdateAaGridlines)
715 ON_COMMAND(ID_CMD_BRIEF, OnCmdBrief)
716 ON_COMMAND(ID_DISABLE_UNDO, OnDisableUndo)
717 ON_UPDATE_COMMAND_UI(ID_DISABLE_UNDO, OnUpdateDisableUndo)
718 ON_UPDATE_COMMAND_UI(ID_CMD_BRIEF, OnUpdateCmdBrief)
719 ON_COMMAND(ID_NEXT_SUBSYS, OnNextSubsys)
720 ON_COMMAND(ID_PREV_SUBSYS, OnPrevSubsys)
721 ON_COMMAND(ID_CANCEL_SUBSYS, OnCancelSubsys)
722 ON_COMMAND(ID_DUMP_STATS, OnDumpStats)
724 ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
725 ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
726 ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
727 ON_COMMAND_RANGE(ID_GROUP1, ID_GROUP9, OnGroup)
728 ON_COMMAND_RANGE(ID_SET_GROUP1, ID_SET_GROUP9, OnSetGroup)
731 /////////////////////////////////////////////////////////////////////////////
732 // CFREDView construction/destruction
734 CFREDView::CFREDView()
736 //m_ConfirmDeleting = TRUE;
737 //m_ShowCapitalShips = TRUE;
738 //m_ShowElevations = TRUE;
739 //m_ShowFighters = TRUE;
741 //m_ShowMiscObjects = TRUE;
742 //m_ShowPlanets = TRUE;
743 //m_ShowWaypoints = TRUE;
745 m_pGDlg = new CGrid(this);
749 //if (!(int errno = gr_init(640, 480, 32)))
750 // Error(LOCATION, "Hey, gr_init failed! Error code = %i", errno);
751 Fred_view_wnd = this;
754 CFREDView::~CFREDView()
761 void CALLBACK expire_game_proc( HWND wnd, UINT uMsg, UINT idEvent, DWORD dwTime)
764 if ( expire_game == EXPIRE_BAD_CHECKSUM )
765 MessageBox (wnd, "Fred can no longer run due to internal overlay error", NULL, MB_OK | MB_ICONERROR |MB_TASKMODAL|MB_SETFOREGROUND);
767 MessageBox (wnd, "Error: cannot enter DOS mode for 80x40 color text mode display.", NULL, MB_OK | MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND);
771 BOOL CFREDView::PreCreateWindow(CREATESTRUCT& cs)
775 casperl = CView::PreCreateWindow(cs);
776 cs.y = 0; // doesn't seem to do anything. :(
778 // other miscellaneous initializations
779 cfile_chdir("data\\missions");
780 set_physics_controls();
784 /////////////////////////////////////////////////////////////////////////////
787 void CFREDView::OnDraw(CDC* pDC)
791 CFREDDoc* pDoc = GetDocument();
798 pDC->GetClipBox(&clip);
799 gr_set_clip(clip.left, clip.top, clip.right - clip.left + 1, clip.bottom - clip.top + 1);
800 SDL_assert(clip.left <= clip.right);
801 SDL_assert(clip.top <= clip.bottom);
802 gr_flip_window((uint) pDC->m_hDC, clip.left, clip.top,
803 clip.right - clip.left + 1, clip.bottom - clip.top + 1);
806 /////////////////////////////////////////////////////////////////////////////
807 // CFREDView printing
809 BOOL CFREDView::OnPreparePrinting(CPrintInfo* pInfo)
811 // default preparation
812 return DoPreparePrinting(pInfo);
815 void CFREDView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
817 // TODO: add extra initialization before printing
820 void CFREDView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
822 // TODO: add cleanup after printing
825 /////////////////////////////////////////////////////////////////////////////
826 // CFREDView diagnostics
829 void CFREDView::AssertValid() const
831 CView::AssertValid();
834 void CFREDView::Dump(CDumpContext& dc) const
839 CFREDDoc* CFREDView::GetDocument() // non-debug version is inline
841 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFREDDoc)));
842 return (CFREDDoc*)m_pDocument;
846 /////////////////////////////////////////////////////////////////////////////
847 // CFREDView message handlers
849 void CFREDView::OnViewGrid()
851 Show_grid = !Show_grid;
855 void CFREDView::OnUpdateViewGrid(CCmdUI* pCmdUI)
857 pCmdUI->SetCheck(Show_grid);
860 void CFREDView::OnViewWaypoints()
862 Show_waypoints = !Show_waypoints;
866 void CFREDView::OnUpdateViewWaypoints(CCmdUI* pCmdUI)
868 pCmdUI->SetCheck(Show_waypoints);
871 #define MAX_MOVE_DISTANCE 25.0f
873 // If cur_object_index references a valid object, drag it from its current
874 // location to the new cursor location specified by "point".
875 // It is dragged relative to the main grid. It's y coordinate is not changed.
876 // Return value: 0/1 = didn't/did move object all the way to goal.
879 int z, cobj, flag, rval = 1;
881 float distance_moved = 0.0f;
882 vector cursor_dir, int_pnt;
883 vector movement_vector;
887 // starfield_bitmaps *bmp;
890 if (Bg_bitmap_dialog) {
894 bmp = &Starfield_bitmaps[Cur_bitmap];
895 if (Single_axis_constraint && Constraint.z) {
896 bmp->dist *= 1.0f + mouse_dx / -800.0f;
897 calculate_bitmap_points(bmp, 0.0f);
900 g3_point_to_vec_delayed(&bmp->m.fvec, marking_box.x2, marking_box.y2);
901 vm_orthogonalize_matrix(&bmp->m);
902 calculate_bitmap_points(bmp, 0.0f);
908 if (!query_valid_object())
911 if ((Dup_drag == 1) && (Briefing_dialog))
915 dup_object(NULL); // reset waypoint list
916 cobj = Duped_wing = -1;
918 objp = GET_FIRST(&obj_used_list);
919 while (objp != END_OF_LIST(&obj_used_list)) {
920 SDL_assert(objp->type != OBJ_NONE);
921 if (objp->flags & OF_MARKED) {
922 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
923 z = Ships[objp->instance].wingnum;
926 else if (Duped_wing != z)
933 z = dup_object(objp);
939 if (cur_object_index == OBJ_INDEX(objp) )
943 objp = GET_NEXT(objp);
946 obj_merge_created_list();
948 objp = GET_FIRST(&obj_used_list);
949 while (objp != END_OF_LIST(&obj_used_list)) {
950 ptr = GET_NEXT(objp);
951 if (objp->flags & OF_TEMP_MARKED)
963 objp = GET_FIRST(&obj_used_list);
964 while (objp != END_OF_LIST(&obj_used_list)) {
965 if (objp->flags & OF_TEMP_MARKED) {
966 objp->flags &= ~OF_TEMP_MARKED;
967 mark_object(OBJ_INDEX(objp));
970 objp = GET_NEXT(objp);
973 set_cur_object_index(cobj);
974 if (Duped_wing != -1)
975 Dup_drag = DUP_DRAG_OF_WING; // indication for later that we duped objects in a wing
979 drag_rotate_save_backup();
984 objp = &Objects[cur_object_index];
985 SDL_assert(objp->type != OBJ_NONE);
986 obj = int_pnt = objp->pos;
988 // Get 3d vector specified by mouse cursor location.
989 g3_point_to_vec_delayed(&cursor_dir, marking_box.x2, marking_box.y2);
990 if (Single_axis_constraint) {
991 // if (fvi_ray_plane(&int_pnt, &obj, &view_orient.fvec, &view_pos, &cursor_dir, 0.0f) >= 0.0f ) {
992 // vm_vec_add(&p1, &obj, &Constraint);
993 // find_nearest_point_on_line(&nearest_point, &obj, &p1, &int_pnt);
994 // int_pnt = nearest_point;
995 // distance_moved = vm_vec_dist(&obj, &int_pnt);
998 vector tmpAnticonstraint = Anticonstraint;
999 vector tmpObject = obj;
1001 tmpAnticonstraint.x = 0.0f;
1002 r = fvi_ray_plane(&int_pnt, &tmpObject, &tmpAnticonstraint, &view_pos, &cursor_dir, 0.0f);
1004 // If intersected behind viewer, don't move. Too confusing, not what user wants.
1005 vm_vec_sub(&vec1, &int_pnt, &view_pos);
1006 vm_vec_sub(&vec2, &obj, &view_pos);
1007 if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f)) {
1009 vm_vec_sub( &tmp1, &int_pnt, &obj );
1010 tmp1.x *= Constraint.x;
1011 tmp1.y *= Constraint.y;
1012 tmp1.z *= Constraint.z;
1013 vm_vec_add( &int_pnt, &obj, &tmp1 );
1015 distance_moved = vm_vec_dist(&obj, &int_pnt);
1019 } else { // Move in x-z plane, defined by grid. Preserve height.
1020 r = fvi_ray_plane(&int_pnt, &obj, &Anticonstraint, &view_pos, &cursor_dir, 0.0f);
1022 // If intersected behind viewer, don't move. Too confusing, not what user wants.
1023 vm_vec_sub(&vec1, &int_pnt, &view_pos);
1024 vm_vec_sub(&vec2, &obj, &view_pos);
1025 if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f))
1026 distance_moved = vm_vec_dist(&obj, &int_pnt);
1029 // If moved too far, then move max distance along vector.
1030 vm_vec_sub(&movement_vector, &int_pnt, &obj);
1031 /* if (distance_moved > MAX_MOVE_DISTANCE) {
1032 vm_vec_normalize(&movement_vector);
1033 vm_vec_scale(&movement_vector, MAX_MOVE_DISTANCE);
1036 if (distance_moved) {
1037 objp = GET_FIRST(&obj_used_list);
1038 while (objp != END_OF_LIST(&obj_used_list)) {
1039 SDL_assert(objp->type != OBJ_NONE);
1040 if (objp->flags & OF_MARKED) {
1041 vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
1042 if (objp->type == OBJ_WAYPOINT) {
1043 Waypoint_lists[objp->instance / 65536].waypoints[objp->instance & 0xffff] =
1048 objp = GET_NEXT(objp);
1051 objp = GET_FIRST(&obj_used_list);
1052 while (objp != END_OF_LIST(&obj_used_list)) {
1053 if (objp->flags & OF_MARKED)
1056 objp = GET_NEXT(objp);
1060 if (Briefing_dialog)
1061 Briefing_dialog->update_positions();
1067 void drag_rotate_save_backup()
1072 if (Cur_bitmap != -1)
1073 bitmap_matrix_backup = Starfield_bitmaps[Cur_bitmap].m;
1076 objp = GET_FIRST(&obj_used_list);
1077 while (objp != END_OF_LIST(&obj_used_list)) {
1078 SDL_assert(objp->type != OBJ_NONE);
1079 if (objp->flags & OF_MARKED) {
1080 rotation_backup[OBJ_INDEX(objp)].pos = objp->pos;
1081 rotation_backup[OBJ_INDEX(objp)].orient = objp->orient;
1084 objp = GET_NEXT(objp);
1088 int drag_rotate_objects()
1091 vector int_pnt, obj;
1093 matrix leader_orient, leader_transpose, tmp, newmat, rotmat;
1094 object *leader, *objp;
1095 // starfield_bitmaps *bmp;
1099 if (Bg_bitmap_dialog) {
1103 bmp = &Starfield_bitmaps[Cur_bitmap];
1104 calculate_bitmap_points(bmp, mouse_dx / -300.0f);
1109 if (!query_valid_object()){
1113 objp = &Objects[cur_object_index];
1114 SDL_assert(objp->type != OBJ_NONE);
1115 obj = int_pnt = objp->pos;
1117 memset(&a, 0, sizeof(angles));
1118 if (Single_axis_constraint) {
1120 a.p = mouse_dy / REDUCER;
1121 else if (Constraint.y)
1122 a.h = mouse_dx / REDUCER;
1123 else if (Constraint.z)
1124 a.b = -mouse_dx / REDUCER;
1127 if (!Constraint.x) { // yz
1128 a.b = -mouse_dx / REDUCER;
1129 a.h = mouse_dy / REDUCER;
1130 } else if (!Constraint.y) { // xz
1131 a.p = mouse_dy / REDUCER;
1132 a.b = -mouse_dx / REDUCER;
1133 } else if (!Constraint.z) { // xy
1134 a.p = mouse_dy / REDUCER;
1135 a.h = mouse_dx / REDUCER;
1139 leader = &Objects[cur_object_index];
1140 leader_orient = leader->orient; // save original orientation
1141 vm_copy_transpose_matrix(&leader_transpose, &leader_orient);
1143 vm_angles_2_matrix(&rotmat, &a);
1144 vm_matrix_x_matrix(&newmat, &leader->orient, &rotmat);
1145 leader->orient = newmat;
1147 objp = GET_FIRST(&obj_used_list);
1148 while (objp != END_OF_LIST(&obj_used_list)) {
1149 SDL_assert(objp->type != OBJ_NONE);
1150 if ((objp->flags & OF_MARKED) && (cur_object_index != OBJ_INDEX(objp) )) {
1153 vector tmpv1, tmpv2;
1155 // change rotation matrix to rotate in opposite direction. This rotation
1156 // matrix is what the leader ship has rotated by.
1157 vm_copy_transpose_matrix(&rot_trans, &rotmat);
1159 // get point relative to our point of rotation (make POR the origin).
1160 vm_vec_sub(&tmpv1, &objp->pos, &leader->pos);
1162 // convert point from real-world coordinates to leader's relative coordinate
1163 // system (z=forward vec, y=up vec, x=right vec
1164 vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient);
1166 // now rotate the point by the transpose from above.
1167 vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
1169 // convert point back into real-world coordinates
1170 vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
1172 // and move origin back to real-world origin. Object is now at it's correct
1174 vm_vec_add(&objp->pos, &leader->pos, &tmpv2);
1176 // Now fix the object's orientation to what it should be.
1177 vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
1178 vm_orthogonalize_matrix(&tmp); // safety check
1182 vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
1187 objp = GET_NEXT(objp);
1190 objp = GET_FIRST(&obj_used_list);
1191 while (objp != END_OF_LIST(&obj_used_list)) {
1192 if (objp->flags & OF_MARKED)
1195 objp = GET_NEXT(objp);
1207 if (Bg_bitmap_dialog) {
1208 SDL_assert(!vm_check_matrix_for_zeros(&bitmap_matrix_backup));
1209 Starfield_bitmaps[Cur_bitmap].m = bitmap_matrix_backup;
1210 calculate_bitmap_points(&Starfield_bitmaps[Cur_bitmap], 0.0f);
1211 button_down = box_marking = 0;
1218 if (Editing_mode == 1) {
1219 vector movement_vector;
1222 if (query_valid_object()) {
1223 objp = &Objects[cur_object_index];
1224 SDL_assert(objp->type != OBJ_NONE);
1225 vm_vec_sub(&movement_vector, &original_pos, &objp->pos);
1227 objp = GET_FIRST(&obj_used_list);
1228 while (objp != END_OF_LIST(&obj_used_list)) {
1229 SDL_assert(objp->type != OBJ_NONE);
1230 if (objp->flags & OF_MARKED)
1231 vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
1233 objp = GET_NEXT(objp);
1237 } else if (Editing_mode == 2) {
1240 objp = GET_FIRST(&obj_used_list);
1241 while (objp != END_OF_LIST(&obj_used_list)) {
1242 SDL_assert(objp->type != OBJ_NONE);
1243 if (objp->flags & OF_MARKED) {
1244 int obj_index = OBJ_INDEX(objp);
1246 if(!IS_VEC_NULL(&rotation_backup[obj_index].orient.rvec) &&
1247 !IS_VEC_NULL(&rotation_backup[obj_index].orient.uvec) &&
1248 !IS_VEC_NULL(&rotation_backup[obj_index].orient.fvec)){
1250 objp->pos = rotation_backup[obj_index].pos;
1251 objp->orient = rotation_backup[obj_index].orient;
1255 objp = GET_NEXT(objp);
1260 button_down = box_marking = 0;
1261 if (Briefing_dialog)
1262 Briefing_dialog->update_positions();
1265 void CFREDView::OnLButtonDown(UINT nFlags, CPoint point)
1270 CView::OnLButtonDown(nFlags, point);
1274 if (cur_waypoint != -1)
1275 list = cur_waypoint_list * 65536 + cur_waypoint;
1277 marking_box.x1 = point.x;
1278 marking_box.y1 = point.y;
1281 on_object = select_object(point.x, point.y);
1284 drag_rotate_save_backup();
1286 if (nFlags & MK_CONTROL) { // add a new object
1287 if (!Bg_bitmap_dialog) {
1288 if (on_object == -1) {
1289 Selection_lock = 0; // force off selection lock
1290 on_object = create_object_on_grid(list);
1297 Selection_lock = 0; // force off selection lock
1298 on_object = Cur_bitmap = create_bg_bitmap();
1299 Bg_bitmap_dialog->update_data();
1301 if (Cur_bitmap == -1)
1302 MessageBox("Background bitmap limit reached.\nCan't add more.");
1306 } else if (!Selection_lock) {
1307 if (Bg_bitmap_dialog) {
1308 Cur_bitmap = on_object;
1309 Bg_bitmap_dialog -> update_data();
1311 } else if ((nFlags & MK_SHIFT) || (on_object == -1) || !(Objects[on_object].flags & OF_MARKED)) {
1312 if (!(nFlags & MK_SHIFT))
1315 if (on_object != -1) {
1316 if (Objects[on_object].flags & OF_MARKED)
1317 unmark_object(on_object);
1319 mark_object(on_object);
1324 if (query_valid_object())
1325 original_pos = Objects[cur_object_index].pos;
1328 if (Selection_lock) {
1329 if (Editing_mode == 1)
1331 else if (Editing_mode == 2)
1332 drag_rotate_objects();
1337 if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
1338 SDL_assert(Briefing_dialog);
1339 Briefing_dialog->icon_select(Objects[cur_object_index].instance);
1342 if (Briefing_dialog)
1343 Briefing_dialog->icon_select(-1);
1346 CView::OnLButtonDown(nFlags, point);
1349 void CFREDView::OnMouseMove(UINT nFlags, CPoint point)
1351 mouse_dx = point.x - last_mouse_x;
1352 mouse_dy = point.y - last_mouse_y;
1353 last_mouse_x = marking_box.x2 = point.x;
1354 last_mouse_y = marking_box.y2 = point.y;
1355 Cursor_over = select_object(point.x, point.y);
1357 if (!(nFlags & MK_LBUTTON))
1360 // The following will cancel a drag operation if another program running in memory
1361 // happens to jump in and take over (such as new email has arrived popup boxes).
1362 if (button_down && GetCapture() != this)
1365 if (!button_down && GetCapture() == this)
1369 if (abs(marking_box.x1 - marking_box.x2) > 1 || abs(marking_box.y1 - marking_box.y2) > 1)
1373 if (on_object != -1 || Selection_lock) {
1374 if (Editing_mode == 1)
1376 else if (Editing_mode == 2)
1377 drag_rotate_objects();
1379 } else if (!Bg_bitmap_dialog)
1382 if (mouse_dx || mouse_dy)
1387 CView::OnMouseMove(nFlags, point);
1390 void CFREDView::OnLButtonUp(UINT nFlags, CPoint point)
1392 marking_box.x2 = point.x;
1393 marking_box.y2 = point.y;
1395 if (button_down && GetCapture() != this)
1398 if (GetCapture() == this)
1402 if ((abs(marking_box.x1 - marking_box.x2) > 1) || (abs(marking_box.y1 - marking_box.y2) > 1))
1406 if ((on_object != -1) || Selection_lock) {
1407 if (Editing_mode == 1)
1409 else if ((Editing_mode == 2) || (Editing_mode == 3))
1410 drag_rotate_objects();
1413 FREDDoc_ptr->autosave("object move");
1419 if (Bg_bitmap_dialog) {
1427 } else if ((!moved && on_object != -1) && !Selection_lock && !(nFlags & MK_SHIFT)) {
1429 mark_object(on_object);
1435 if (Dup_drag == DUP_DRAG_OF_WING) {
1440 sprintf(msg, "Add cloned ships to wing %s?", Wings[Duped_wing].name);
1441 if (MessageBox(msg, "Query", MB_YESNO) == IDYES) {
1442 objp = GET_FIRST(&obj_used_list);
1443 while (objp != END_OF_LIST(&obj_used_list)) {
1444 if (objp->flags & OF_MARKED) {
1445 if (Wings[Duped_wing].wave_count >= MAX_SHIPS_PER_WING) {
1446 MessageBox("Max ships per wing limit reached");
1450 // Can't do player starts, since only player 1 is currently allowed to be in a wing
1452 SDL_assert(objp->type == OBJ_SHIP);
1453 ship = objp->instance;
1454 SDL_assert(Ships[ship].wingnum == -1);
1455 sprintf(Ships[ship].ship_name, "%s %d", Wings[Duped_wing].name,
1456 Wings[Duped_wing].wave_count + 1);
1458 Wings[Duped_wing].ship_index[Wings[Duped_wing].wave_count] = ship;
1459 Ships[ship].wingnum = Duped_wing;
1461 wing_objects[Duped_wing][Wings[Duped_wing].wave_count] = OBJ_INDEX(objp);
1462 Wings[Duped_wing].wave_count++;
1465 objp = GET_NEXT(objp);
1471 if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
1472 SDL_assert(Briefing_dialog);
1473 Briefing_dialog->icon_select(Objects[cur_object_index].instance);
1476 if (Briefing_dialog)
1477 Briefing_dialog->icon_select(-1);
1480 CView::OnLButtonUp(nFlags, point);
1483 // This function never gets called because nothing causes
1484 // the WM_GOODBYE event to occur.
1485 // False! When you close the Ship Dialog, this function is called! --MK, 8/30/96
1486 LONG CFREDView::OnGoodbye(UINT wParam, LONG lParam)
1488 Ship_editor_dialog.DestroyWindow();
1489 Wing_editor_dialog.DestroyWindow();
1494 void CFREDView::OnEditorsShips()
1498 SDL_assert(Ship_editor_dialog.GetSafeHwnd());
1499 if (!Show_sexp_help)
1500 adjust = -SEXP_HELP_BOX_SIZE;
1502 if (!theApp.init_window(&Ship_wnd_data, &Ship_editor_dialog, adjust))
1505 Ship_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
1506 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
1507 Ship_editor_dialog.ShowWindow(SW_RESTORE);
1510 void CFREDView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT lParam)
1514 lKeyData = lParam & 255; // key data
1515 if (lParam & 256) lKeyData += 0x80;
1516 key_mark(lKeyData, 1, 0);
1518 CView::OnKeyDown(nChar, nRepCnt, lParam);
1521 void CFREDView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT lParam)
1525 lKeyData = lParam & 255; // key data
1526 if (lParam & 256) lKeyData += 0x80;
1527 key_mark(lKeyData, 0, 0);
1529 CView::OnKeyUp(nChar, nRepCnt, lParam);
1532 void CFREDView::OnSetFocus(CWnd* pOldWnd)
1534 static int flag = 0;
1540 nprintf(("Fred routing", "OnSetFocus() called\n"));
1542 Ship_editor_dialog.initialize_data(1);
1547 Wing_editor_dialog.initialize_data(1);
1551 /* if (Wing_editor_dialog.verify() == -1)
1554 if (Ship_editor_dialog.verify() == -1)
1557 if (update_dialog_boxes()) {
1558 nprintf(("Fred routing", "OnSetFocus() returned (error occured)\n"));
1560 Ship_editor_dialog.bypass_errors = 0;
1561 Wing_editor_dialog.bypass_errors = 0;
1565 if (Local_modified) {
1566 FREDDoc_ptr->autosave("Editing");
1571 CView::OnSetFocus(pOldWnd);
1572 nprintf(("Fred routing", "Main window focus accepted\n"));
1576 if (GetActiveWindow() != Fred_main_wnd) {
1577 Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1578 nprintf(("Fred routing", "OnSetFocus() had to put main window back on top\n"));
1584 void CFREDView::OnKillFocus(CWnd* pNewWnd)
1586 nprintf(("Fred routing", "OnKillFocus() called\n"));
1589 CView::OnKillFocus(pNewWnd);
1594 void CFREDView::OnSize(UINT nType, int cx, int cy)
1596 CView::OnSize(nType, cx, cy);
1598 if ((cx > 0) && (cy > 0)) {
1599 gr_init(GR_640, GR_SOFTWARE, 8, cx, cy);
1603 void do_trackball_stuff(int nFlags, CPoint point)
1607 if (nFlags & MK_LBUTTON){
1610 if (nFlags & MK_RBUTTON){
1614 move_mouse(btn, point.x, point.y);
1617 // If add_flag != 0, then add found objects to current wing, else create new wing.
1618 void select_objects()
1620 int x, y, valid, icon_mode = 0;
1624 if (marking_box.x1 > marking_box.x2) {
1626 marking_box.x1 = marking_box.x2;
1630 if (marking_box.y1 > marking_box.y2) {
1632 marking_box.y1 = marking_box.y2;
1636 ptr = GET_FIRST(&obj_used_list);
1637 while (ptr != END_OF_LIST(&obj_used_list)) {
1639 if (ptr->flags & OF_HIDDEN)
1642 SDL_assert(ptr->type != OBJ_NONE);
1643 switch (ptr->type) {
1645 if (!Show_waypoints)
1657 switch (Ships[ptr->instance].team) {
1677 g3_rotate_vertex(&v, &ptr->pos);
1678 if (!(v.codes & CC_BEHIND) && valid)
1679 if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
1683 if (x >= marking_box.x1 && x <= marking_box.x2 && y >= marking_box.y1 && y <= marking_box.y2) {
1684 if (ptr->flags & OF_MARKED)
1685 unmark_object(OBJ_INDEX(ptr));
1687 mark_object(OBJ_INDEX(ptr));
1689 if (ptr->type == OBJ_POINT)
1694 ptr = GET_NEXT(ptr);
1698 ptr = GET_FIRST(&obj_used_list);
1699 while (ptr != END_OF_LIST(&obj_used_list)) {
1700 if ((ptr->flags & OF_MARKED) && (ptr->type != OBJ_POINT))
1701 unmark_object(OBJ_INDEX(ptr));
1703 ptr = GET_NEXT(ptr);
1707 Update_ship = Update_wing = 1;
1710 LONG CFREDView::OnMenuPopupShips(UINT wParam, LONG lParam)
1715 point = * ((CPoint*) lParam);
1717 ClientToScreen(&point);
1719 menu.LoadMenu(IDR_MENU_SHIP_POPUP);
1720 menu.GetSubMenu(0)->TrackPopupMenu(
1721 TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1726 LONG CFREDView::OnMenuPopupEdit(UINT wParam, LONG lParam)
1731 point = * ((CPoint*) lParam);
1733 ClientToScreen(&point);
1735 menu.LoadMenu(IDR_MENU_EDIT_POPUP);
1736 menu.GetSubMenu(0)->TrackPopupMenu(
1737 TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1742 int g_Ships_as_icons = 0;
1744 void CFREDView::OnMiscstuffShowshipsasicons()
1747 if (g_Ships_as_icons == 0)
1748 g_Ships_as_icons = 1;
1750 g_Ships_as_icons = 0;
1753 // right mouse button popup menu stuff
1754 void CFREDView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
1756 // make sure window is active
1757 // GetParentFrame()->ActivateFrame();
1761 CPoint local = point;
1768 ScreenToClient(&local);
1769 objnum = select_object(local.x, local.y);
1772 set_cur_object_index(objnum);
1773 if (menu.LoadMenu(IDR_MENU_SHIP_POPUP)) {
1774 int id = ID_EDITORS_SHIPS;
1775 CMenu* pPopup = menu.GetSubMenu(0);
1777 ASSERT(pPopup != NULL);
1779 pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, ID_EDITORS_SHIPS, "Edit Marked Ships");
1783 if ((Objects[objnum].type == OBJ_START) || (Objects[objnum].type == OBJ_SHIP))
1784 str.Format("Edit %s", Ships[Objects[objnum].instance].ship_name);
1786 else if (Objects[objnum].type == OBJ_JUMP_NODE) {
1787 id = ID_EDITORS_WAYPOINT;
1788 str.Format("Edit %s", Jump_nodes[Objects[objnum].instance].name);
1790 } else if (Objects[objnum].type == OBJ_WAYPOINT) {
1791 id = ID_EDITORS_WAYPOINT;
1792 str.Format("Edit %s:%d", Waypoint_lists[Objects[objnum].instance / 65536].name,
1793 (Objects[objnum].instance & 0xffff) + 1);
1795 } else if (Objects[objnum].type == OBJ_POINT) {
1800 str = _T("Unknown");
1803 pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, id, str);
1806 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()); // use main window for cmds
1810 if (menu.LoadMenu(IDR_MENU_EDIT_POPUP)) {
1812 CMenu* pPopup = menu.GetSubMenu(0);
1813 CMenu shipPopup, player_submenu, species_submenu[MAX_SPECIES_NAMES];
1814 ASSERT(pPopup != NULL);
1816 // create a popup menu based on the ship models read in ship.cpp.
1817 shipPopup.CreatePopupMenu();
1818 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_waypoint, "Waypoint");
1819 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_start, "Player Start");
1820 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_jump_node, "Jump Node");
1821 for (i=0; i<MAX_SPECIES_NAMES; i++) {
1822 species_submenu[i].CreatePopupMenu();
1823 shipPopup.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1824 (UINT) species_submenu[i].m_hMenu, Species_names[i]);
1827 for (i=0; i<Num_ship_types; i++)
1828 species_submenu[Ship_info[i].species].AppendMenu(MF_STRING |
1829 MF_ENABLED, SHIP_TYPES + i, Ship_info[i].name);
1831 pPopup->AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1832 (UINT) shipPopup.m_hMenu, "New Object Type");
1834 CWnd::DrawMenuBar(); // AppendMenu documentation says to do this.
1835 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
1840 void CFREDView::OnEditPopupShowShipIcons()
1842 Show_ship_info = !Show_ship_info;
1843 theApp.write_ini_file();
1847 void CFREDView::OnUpdateEditPopupShowShipIcons(CCmdUI* pCmdUI)
1849 pCmdUI->SetCheck(Show_ship_info);
1852 void CFREDView::OnEditPopupShowShipModels()
1854 Show_ship_models = !Show_ship_models;
1855 theApp.write_ini_file();
1859 void CFREDView::OnUpdateEditPopupShowShipModels(CCmdUI* pCmdUI)
1861 pCmdUI->SetCheck(Show_ship_models);
1864 void CFREDView::OnEditPopupShowCompass()
1866 Show_compass = !Show_compass;
1867 theApp.write_ini_file();
1871 void CFREDView::OnUpdateEditPopupShowCompass(CCmdUI* pCmdUI)
1873 pCmdUI->SetCheck(Show_compass);
1876 // View implementation file
1877 CFREDView *CFREDView::GetView()
1879 CFrameWnd *pFrame = (CFrameWnd *) (AfxGetApp()->m_pMainWnd);
1881 CView *pView = pFrame->GetActiveView();
1886 // Fail if view is of wrong kind
1887 // (this could occur with splitter windows, or additional
1888 // views on a single document
1889 if (! pView->IsKindOf(RUNTIME_CLASS(CFREDView)))
1892 return (CFREDView *) pView;
1895 /*void CFREDView::OnShipType0()
1897 cur_model_index = 1;
1900 void CFREDView::OnShipType1()
1902 cur_model_index = 2;
1905 void CFREDView::OnShipType2()
1907 cur_model_index = 3;
1910 void CFREDView::OnShipType3()
1912 cur_model_index = 4;
1915 void CFREDView::OnShipType4()
1917 cur_model_index = 5;
1920 void CFREDView::OnShipType5()
1922 cur_model_index = 6;
1925 void CFREDView::OnUpdateShipType1(CCmdUI* pCmdUI)
1927 pCmdUI->SetCheck(cur_model_index == 2);
1930 void CFREDView::OnUpdateShipType2(CCmdUI* pCmdUI)
1932 pCmdUI->SetCheck(cur_model_index == 3);
1935 void CFREDView::OnUpdateShipType3(CCmdUI* pCmdUI)
1937 pCmdUI->SetCheck(cur_model_index == 4);
1940 void CFREDView::OnUpdateShipType4(CCmdUI* pCmdUI)
1942 pCmdUI->SetCheck(cur_model_index == 5);
1945 void CFREDView::OnUpdateShipType5(CCmdUI* pCmdUI)
1947 pCmdUI->SetCheck(cur_model_index == 6);
1951 void CFREDView::OnUpdateShipType0(CCmdUI* pCmdUI)
1953 pCmdUI->SetCheck(cur_model_index == 1);
1957 void CFREDView::OnEditShipType6()
1959 cur_model_index = 7;
1963 void CFREDView::OnUpdateEditShipType6(CCmdUI* pCmdUI)
1965 pCmdUI->SetCheck(cur_model_index == 7);
1969 // following code added by MWA 09/04/96
1970 // Implements messages for popup menu built on the fly.
1971 // not sure how stable the code is, but appears to work for now.
1972 // id's for the menu items are simply the model numbers for
1973 // the ships. Shouldn't conflict with any other ID_* thingys.
1974 BOOL CFREDView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
1978 if (!pHandlerInfo) {
1979 if ((id >= SHIP_TYPES) && (id < SHIP_TYPES + Num_ship_types + 3)) {
1980 if (nCode == CN_COMMAND) {
1981 cur_model_index = id - SHIP_TYPES;
1982 m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
1984 } else if (nCode == CN_UPDATE_COMMAND_UI) {
1985 // Update UI element state
1986 ((CCmdUI*) pExtra)->SetCheck(cur_model_index + SHIP_TYPES == id);
1987 ((CCmdUI*) pExtra)->Enable(TRUE);
1994 return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
1997 void CFREDView::OnMiscStatistics()
2002 "Number of Objects: %d\n"
2003 "Number of Ships: %d\n"
2004 "Number of Wings: %d\n",
2005 num_objects, ship_get_num_ships(), num_wings);
2007 MessageBox(buf, "FRED Statistics");
2010 void CFREDView::OnUpdateChangeViewpointExternal(CCmdUI* pCmdUI)
2012 pCmdUI->SetCheck(!viewpoint);
2015 void CFREDView::OnChangeViewpointExternal()
2021 void CFREDView::OnUpdateChangeViewpointFollow(CCmdUI* pCmdUI)
2023 pCmdUI->SetCheck(viewpoint == 1);
2026 void CFREDView::OnChangeViewpointFollow()
2029 view_obj = cur_object_index;
2033 void CFREDView::OnEditorsGoals()
2035 CMissionGoalsDlg dlg;
2040 void CFREDView::OnSpeed1()
2043 set_physics_controls();
2046 void CFREDView::OnSpeed2()
2049 set_physics_controls();
2052 void CFREDView::OnSpeed3()
2055 set_physics_controls();
2058 void CFREDView::OnSpeed5()
2061 set_physics_controls();
2064 void CFREDView::OnSpeed8()
2067 set_physics_controls();
2070 void CFREDView::OnSpeed10()
2073 set_physics_controls();
2076 void CFREDView::OnSpeed50()
2079 set_physics_controls();
2082 void CFREDView::OnSpeed100()
2084 physics_speed = 100;
2085 set_physics_controls();
2088 void CFREDView::OnRot1()
2091 set_physics_controls();
2094 void CFREDView::OnRot2()
2097 set_physics_controls();
2100 void CFREDView::OnRot3()
2103 set_physics_controls();
2106 void CFREDView::OnRot4()
2109 set_physics_controls();
2112 void CFREDView::OnRot5()
2115 set_physics_controls();
2118 void CFREDView::OnUpdateSpeed1(CCmdUI* pCmdUI)
2120 pCmdUI->SetCheck(physics_speed == 1);
2123 void CFREDView::OnUpdateSpeed2(CCmdUI* pCmdUI)
2125 pCmdUI->SetCheck(physics_speed == 2);
2128 void CFREDView::OnUpdateSpeed3(CCmdUI* pCmdUI)
2130 pCmdUI->SetCheck(physics_speed == 3);
2133 void CFREDView::OnUpdateSpeed5(CCmdUI* pCmdUI)
2135 pCmdUI->SetCheck(physics_speed == 5);
2138 void CFREDView::OnUpdateSpeed8(CCmdUI* pCmdUI)
2140 pCmdUI->SetCheck(physics_speed == 8);
2143 void CFREDView::OnUpdateSpeed10(CCmdUI* pCmdUI)
2145 pCmdUI->SetCheck(physics_speed == 10);
2148 void CFREDView::OnUpdateSpeed50(CCmdUI* pCmdUI)
2150 pCmdUI->SetCheck(physics_speed == 50);
2153 void CFREDView::OnUpdateSpeed100(CCmdUI* pCmdUI)
2155 pCmdUI->SetCheck(physics_speed == 100);
2158 void CFREDView::OnUpdateRot1(CCmdUI* pCmdUI)
2160 pCmdUI->SetCheck(physics_rot == 2);
2163 void CFREDView::OnUpdateRot2(CCmdUI* pCmdUI)
2165 pCmdUI->SetCheck(physics_rot == 10);
2168 void CFREDView::OnUpdateRot3(CCmdUI* pCmdUI)
2170 pCmdUI->SetCheck(physics_rot == 25);
2173 void CFREDView::OnUpdateRot4(CCmdUI* pCmdUI)
2175 pCmdUI->SetCheck(physics_rot == 50);
2178 void CFREDView::OnUpdateRot5(CCmdUI* pCmdUI)
2180 pCmdUI->SetCheck(physics_rot == 100);
2183 void CFREDView::OnControlModeCamera()
2188 void CFREDView::OnUpdateControlModeCamera(CCmdUI* pCmdUI)
2190 pCmdUI->SetCheck(!Control_mode);
2193 void CFREDView::OnControlModeShip()
2198 void CFREDView::OnUpdateControlModeShip(CCmdUI* pCmdUI)
2200 pCmdUI->SetCheck(Control_mode == 1);
2203 void CFREDView::OnShowGridPositions()
2205 Show_grid_positions = !Show_grid_positions;
2206 theApp.write_ini_file();
2210 void CFREDView::OnUpdateShowGridPositions(CCmdUI* pCmdUI)
2212 pCmdUI->SetCheck(Show_grid_positions);
2215 void CFREDView::OnShowCoordinates()
2217 Show_coordinates = !Show_coordinates;
2218 theApp.write_ini_file();
2222 void CFREDView::OnUpdateShowCoordinates(CCmdUI* pCmdUI)
2224 pCmdUI->SetCheck(Show_coordinates);
2227 void CFREDView::OnSelect()
2232 void CFREDView::OnUpdateSelect(CCmdUI* pCmdUI)
2234 pCmdUI->SetCheck(!Editing_mode);
2237 void CFREDView::OnSelectAndMove()
2242 void CFREDView::OnUpdateSelectAndMove(CCmdUI* pCmdUI)
2244 pCmdUI->SetCheck(Editing_mode == 1);
2247 void CFREDView::OnSelectAndRotate()
2252 void CFREDView::OnUpdateSelectAndRotate(CCmdUI* pCmdUI)
2254 pCmdUI->SetCheck(Editing_mode == 2);
2257 void CFREDView::OnConstrainX()
2259 vm_vec_make(&Constraint, 1.0f, 0.0f, 0.0f);
2260 vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 1.0f);
2261 Single_axis_constraint = 1;
2264 void CFREDView::OnUpdateConstrainX(CCmdUI* pCmdUI)
2266 pCmdUI->SetRadio(Constraint.x && !Constraint.y && !Constraint.z);
2269 void CFREDView::OnConstrainY()
2271 vm_vec_make(&Constraint, 0.0f, 1.0f, 0.0f);
2272 vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 1.0f);
2273 Single_axis_constraint = 1;
2276 void CFREDView::OnUpdateConstrainY(CCmdUI* pCmdUI)
2278 pCmdUI->SetRadio(!Constraint.x && Constraint.y && !Constraint.z);
2281 void CFREDView::OnConstrainZ()
2283 vm_vec_make(&Constraint, 0.0f, 0.0f, 1.0f);
2284 vm_vec_make(&Anticonstraint, 1.0f, 1.0f, 0.0f);
2285 Single_axis_constraint = 1;
2288 void CFREDView::OnUpdateConstrainZ(CCmdUI* pCmdUI)
2290 pCmdUI->SetRadio(!Constraint.x && !Constraint.y && Constraint.z);
2293 void CFREDView::OnConstrainXz()
2295 vm_vec_make(&Constraint, 1.0f, 0.0f, 1.0f);
2296 vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 0.0f);
2297 Single_axis_constraint = 0;
2300 void CFREDView::OnUpdateConstrainXz(CCmdUI* pCmdUI)
2302 pCmdUI->SetRadio(Constraint.x && !Constraint.y && Constraint.z);
2305 void CFREDView::OnConstrainXy()
2307 vm_vec_make(&Constraint, 1.0f, 1.0f, 0.0f);
2308 vm_vec_make(&Anticonstraint, 0.0f, 0.0f, 1.0f);
2309 Single_axis_constraint = 0;
2312 void CFREDView::OnUpdateConstrainXy(CCmdUI* pCmdUI)
2314 pCmdUI->SetRadio(Constraint.x && Constraint.y && !Constraint.z);
2317 void CFREDView::OnConstrainYz()
2319 vm_vec_make(&Constraint, 0.0f, 1.0f, 1.0f);
2320 vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 0.0f);
2321 Single_axis_constraint = 0;
2324 void CFREDView::OnUpdateConstrainYz(CCmdUI* pCmdUI)
2326 pCmdUI->SetRadio(!Constraint.x && Constraint.y && Constraint.z);
2329 void CFREDView::OnSelectionLock()
2331 Selection_lock = !Selection_lock;
2334 void CFREDView::OnUpdateSelectionLock(CCmdUI* pCmdUI)
2336 pCmdUI->SetCheck(Selection_lock);
2339 void CFREDView::OnLButtonDblClk(UINT nFlags, CPoint point)
2341 CView::OnLButtonDblClk(nFlags, point);
2342 if (Cursor_over != -1) {
2343 switch (Objects[Cursor_over].type) {
2351 OnEditorsWaypoint();
2355 } else if (Briefing_dialog)
2356 Fixed_briefing_size = !Fixed_briefing_size;
2359 void CFREDView::OnDoubleFineGridlines()
2361 double_fine_gridlines = !double_fine_gridlines;
2362 maybe_create_new_grid(The_grid, &eye_pos, &eye_orient, 1);
2363 theApp.write_ini_file();
2367 void CFREDView::OnUpdateDoubleFineGridlines(CCmdUI* pCmdUI)
2369 pCmdUI->SetCheck(double_fine_gridlines);
2372 void CFREDView::OnShowDistances()
2374 Show_distances = !Show_distances;
2375 theApp.write_ini_file();
2379 void CFREDView::OnUpdateShowDistances(CCmdUI* pCmdUI)
2381 pCmdUI->SetCheck(Show_distances);
2384 void CFREDView::OnUniversalHeading()
2386 Universal_heading = !Universal_heading;
2389 void CFREDView::OnUpdateUniversalHeading(CCmdUI* pCmdUI)
2391 pCmdUI->SetCheck(Universal_heading);
2394 void CFREDView::OnFlyingControls()
2396 Flying_controls_mode = !Flying_controls_mode;
2399 void CFREDView::OnUpdateFlyingControls(CCmdUI* pCmdUI)
2401 pCmdUI->SetCheck(Flying_controls_mode);
2404 void CFREDView::OnRotateLocally()
2406 Group_rotate = !Group_rotate;
2409 void CFREDView::OnUpdateRotateLocally(CCmdUI* pCmdUI)
2411 pCmdUI->SetCheck(!Group_rotate);
2414 void CFREDView::OnSelectList()
2421 // position camera to view all objects on the screen at once. Doesn't change orientation.
2422 void view_universe(int just_marked)
2424 int i, max = 0, flags[MAX_OBJECTS];
2425 float dist, largest = 20.0f;
2426 vector center, p1, p2; // center of all the objects collectively
2430 for (i=0; i<MAX_OBJECTS; i++)
2434 ptr = &Objects[cur_object_index];
2436 ptr = GET_FIRST(&obj_used_list);
2438 p1.x = p2.x = ptr->pos.x;
2439 p1.y = p2.y = ptr->pos.y;
2440 p1.z = p2.z = ptr->pos.z;
2442 ptr = GET_FIRST(&obj_used_list);
2443 while (ptr != END_OF_LIST(&obj_used_list)) {
2444 if (!just_marked || (ptr->flags & OF_MARKED)) {
2446 if (center.x < p1.x)
2448 if (center.x > p2.x)
2450 if (center.y < p1.y)
2452 if (center.y > p2.y)
2454 if (center.z < p1.z)
2456 if (center.z > p2.z)
2460 ptr = GET_NEXT(ptr);
2463 vm_vec_avg(¢er, &p1, &p2);
2464 ptr = GET_FIRST(&obj_used_list);
2465 while (ptr != END_OF_LIST(&obj_used_list)) {
2466 if (!just_marked || (ptr->flags & OF_MARKED)) {
2467 dist = vm_vec_dist_squared(¢er, &ptr->pos);
2471 flags[OBJ_INDEX(ptr)] = 1; // flag object as needing on-screen check
2472 if (OBJ_INDEX(ptr) > max)
2473 max = OBJ_INDEX(ptr);
2476 ptr = GET_NEXT(ptr);
2479 dist = fl_sqrt(largest) + 1.0f;
2480 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2481 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2483 ptr = GET_FIRST(&obj_used_list);
2484 while (ptr != END_OF_LIST(&obj_used_list)) {
2485 if (!just_marked || (ptr->flags & OF_MARKED)) {
2486 g3_rotate_vertex(&v, &ptr->pos);
2487 SDL_assert(!(v.codes & CC_BEHIND));
2488 if (g3_project_vertex(&v) & PF_OVERFLOW)
2491 while (v.codes & CC_OFF) { // is point off screen?
2492 dist += 5.0f; // zoom out a little and check again.
2493 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2494 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2495 g3_rotate_vertex(&v, &ptr->pos);
2496 if (g3_project_vertex(&v) & PF_OVERFLOW)
2501 ptr = GET_NEXT(ptr);
2505 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2506 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2510 void CFREDView::cycle_constraint()
2512 if (Single_axis_constraint) {
2515 else if (Constraint.y)
2517 else if (Constraint.z)
2523 else if (!Constraint.y)
2525 else if (!Constraint.z)
2530 void CFREDView::OnZoomExtents()
2535 void CFREDView::OnZoomSelected()
2537 if (query_valid_object()) {
2541 vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.fvec, Objects[cur_object_index].radius * -3.0f);
2547 void CFREDView::OnUpdateZoomSelected(CCmdUI* pCmdUI)
2549 pCmdUI->Enable(query_valid_object());
2552 void CFREDView::OnFormWing()
2555 FREDDoc_ptr->autosave("form wing");
2558 void CFREDView::OnUpdateFormWing(CCmdUI* pCmdUI)
2563 if (query_valid_object()) {
2564 ptr = GET_FIRST(&obj_used_list);
2565 while (ptr != END_OF_LIST(&obj_used_list)) {
2566 if (ptr->flags & OF_MARKED) {
2567 if (ptr->type == OBJ_SHIP)
2568 switch (ship_query_general_type(ptr->instance))
2570 case SHIP_TYPE_FIGHTER_BOMBER:
2571 case SHIP_TYPE_CRUISER:
2572 case SHIP_TYPE_AWACS:
2573 case SHIP_TYPE_GAS_MINER:
2574 case SHIP_TYPE_CORVETTE:
2575 case SHIP_TYPE_FREIGHTER:
2576 case SHIP_TYPE_CAPITAL:
2577 case SHIP_TYPE_TRANSPORT:
2581 if (ptr->type == OBJ_START)
2585 ptr = GET_NEXT(ptr);
2589 pCmdUI->Enable(count > 0);
2592 int query_single_wing_marked()
2596 if (!query_valid_object())
2602 i = Wings[cur_wing].wave_count;
2603 if (Marked != i) // does marked object count match number of ships in wing?
2607 obj = wing_objects[cur_wing][i];
2608 if ((Objects[obj].type != OBJ_SHIP) && (Objects[obj].type != OBJ_START))
2609 Error(LOCATION, "Invalid objects detected in wing \"%s\"", Wings[cur_wing].name);
2611 // if (Ships[Objects[obj].instance].wingnum != cur_wing)
2613 SDL_assert(Ships[Objects[obj].instance].wingnum == cur_wing);
2614 if (!(Objects[obj].flags & OF_MARKED)) // ensure all ships in wing.are marked
2621 void CFREDView::OnDisbandWing()
2623 if (query_single_wing_marked()) {
2624 remove_wing(cur_wing);
2625 FREDDoc_ptr->autosave("wing disband");
2628 MessageBox("One and only one wing must be selected for this operation");
2631 void CFREDView::OnUpdateDisbandWing(CCmdUI* pCmdUI)
2633 pCmdUI->Enable(query_single_wing_marked());
2636 void CFREDView::OnShowHorizon()
2638 Show_horizon = !Show_horizon;
2639 theApp.write_ini_file();
2643 void CFREDView::OnUpdateShowHorizon(CCmdUI* pCmdUI)
2645 pCmdUI->SetCheck(Show_horizon);
2648 void CFREDView::OnEditorsWing()
2652 SDL_assert(Wing_editor_dialog.GetSafeHwnd());
2653 if (!Show_sexp_help)
2654 adjust = -SEXP_HELP_BOX_SIZE;
2656 if (!theApp.init_window(&Wing_wnd_data, &Wing_editor_dialog, adjust))
2659 Wing_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
2660 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2661 Wing_editor_dialog.ShowWindow(SW_RESTORE);
2664 void CFREDView::OnEditorsPlayer()
2666 player_start_editor dlg;
2671 void CFREDView::OnEditorsOrient()
2678 void CFREDView::OnEditorsEvents()
2680 if (Message_editor_dlg) {
2681 MessageBox("You must close the message editor before opening the event editor");
2685 if (!Event_editor_dlg) {
2686 Event_editor_dlg = new event_editor;
2687 Event_editor_dlg->Create(event_editor::IDD);
2690 Event_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2691 Event_editor_dlg->ShowWindow(SW_RESTORE);
2694 void CFREDView::OnUpdateEditorsOrient(CCmdUI* pCmdUI)
2696 pCmdUI->Enable(query_valid_object());
2699 void CFREDView::OnEditorsMessage()
2701 if (Event_editor_dlg) {
2702 MessageBox("You must close the event editor before opening the message editor");
2706 if (!Message_editor_dlg) {
2707 Message_editor_dlg = new CMessageEditorDlg;
2708 Message_editor_dlg->Create(CMessageEditorDlg::IDD);
2711 Message_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2712 Message_editor_dlg->ShowWindow(SW_RESTORE);
2715 void CFREDView::OnEditorsStarfield()
2717 starfield_editor dlg;
2722 void CFREDView::place_background_bitmap(vector v)
2726 void CFREDView::OnEditorsBgBitmaps()
2728 if (!Bg_bitmap_dialog) {
2729 Bg_bitmap_dialog = new bg_bitmap_dlg;
2730 Bg_bitmap_dialog->create();
2733 Bg_bitmap_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
2734 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2735 Bg_bitmap_dialog->ShowWindow(SW_RESTORE);
2738 void CFREDView::OnEditorsReinforcement()
2740 reinforcement_editor_dlg dlg;
2745 void CFREDView::OnErrorChecker()
2749 z = global_error_check();
2751 MessageBox("No errors were detected in this mission", "Woohoo!");
2753 for (z=0; z<obj_count; z++)
2760 int CFREDView::global_error_check()
2762 char buf[256], *str;
2763 int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
2766 int starting_orders;
2769 if ( The_mission.game_type & MISSION_TYPE_MULTI )
2772 // if (!stricmp(The_mission.name, "Untitled"))
2773 // if (error("You haven't given this mission a title yet.\nThis is done from the Mission Specs Editor (Shift-N)."))
2776 // cycle though all the objects and verify every possible aspect of them
2778 ptr = GET_FIRST(&obj_used_list);
2779 while (ptr != END_OF_LIST(&obj_used_list)) {
2780 names[obj_count] = NULL;
2781 flags[obj_count] = 0;
2783 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
2784 if (i < 0 || i >= MAX_SHIPS){
2785 return internal_error("An object has an illegal ship index");
2788 z = Ships[i].ship_info_index;
2789 if ((z < 0) || (z >= Num_ship_types)){
2790 return internal_error("A ship has an illegal class");
2793 if (ptr->type == OBJ_START) {
2795 if (!(Ship_info[z].flags & SIF_PLAYER_SHIP)) {
2796 ptr->type = OBJ_SHIP;
2799 if (error("Invalid ship type for a player. Ship has been reset to non-player ship.")){
2804 for (n=count=0; n<MAX_PRIMARY_BANKS; n++){
2805 if (Ships[i].weapons.primary_bank_weapons[n] >= 0){
2811 if (error("Player \"%s\" has no primary weapons. Should have at least 1", Ships[i].ship_name)){
2816 for (n=count=0; n<MAX_SECONDARY_BANKS; n++){
2817 if (Ships[i].weapons.secondary_bank_weapons[n] >= 0){
2823 if (error("Player \"%s\" has no secondary weapons. Should have at least 1", Ships[i].ship_name)){
2829 if (Ships[i].objnum != OBJ_INDEX(ptr)){
2830 return internal_error("Object/ship references are corrupt");
2833 names[obj_count] = Ships[i].ship_name;
2834 wing = Ships[i].wingnum;
2835 if (wing >= 0) { // ship is part of a wing, so check this
2836 if (wing < 0 || wing >= MAX_WINGS){ // completely out of range?
2837 return internal_error("A ship has an illegal wing index");
2840 j = Wings[wing].wave_count;
2842 return internal_error("A ship is in a non-existant wing");
2845 if (j < 0 || j > MAX_SHIPS_PER_WING){
2846 return internal_error("Invalid number of ships in wing \"%s\"", Wings[z].name);
2850 if (wing_objects[wing][j] == OBJ_INDEX(ptr)){ // look for object in wing's table
2856 return internal_error("Ship/wing references are corrupt");
2860 if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (Ships[i].hotkey >= 0) ){
2861 if (error("Ship flagged as \"destroy before mission start\" has a hotkey assignment")){
2866 if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (ptr->type == OBJ_START) ){
2867 if (error("Player start flagged as \"destroy before mission start\"")){
2871 } else if (ptr->type == OBJ_WAYPOINT) {
2872 j = i / 65536; // waypoint path number
2873 z = i & 0xffff; // waypoint number in path
2874 if (j < 0 || j >= Num_waypoint_lists){
2875 return internal_error("Object references an illegal waypoint path number");
2878 if (z >= Waypoint_lists[j].count){
2879 return internal_error("Object references an illegal waypoint number in path");
2882 sprintf(buf, "%s:%d", Waypoint_lists[j].name, z + 1);
2883 names[obj_count] = new char[strlen(buf) + 1];
2884 strcpy(names[obj_count], buf);
2885 flags[obj_count] = 1;
2886 } else if (ptr->type == OBJ_POINT) {
2887 if (!Briefing_dialog){
2888 return internal_error("Briefing icon detected when not in briefing edit mode");
2890 } else if (ptr->type == OBJ_JUMP_NODE) {
2891 if (i < 0 || i >= Num_jump_nodes){
2892 return internal_error("Object has illegal jump node index");
2895 return internal_error("An unknown object type (%d) was detected", ptr->type);
2898 for (i=0; i<obj_count; i++){
2899 if (names[i] && names[obj_count]){
2900 if (!stricmp(names[i], names[obj_count])){
2901 return internal_error("Duplicate object names (%s)", names[i]);
2907 ptr = GET_NEXT(ptr);
2910 if (t != Player_starts){
2911 return internal_error("Total number of player ships is incorrect");
2914 if (obj_count != num_objects){
2915 return internal_error("num_objects is incorrect");
2919 for (i=0; i<MAX_SHIPS; i++) {
2920 if (Ships[i].objnum >= 0) { // is ship being used?
2922 if (!query_valid_object(Ships[i].objnum)){
2923 return internal_error("Ship uses an unused object");
2926 z = Objects[Ships[i].objnum].type;
2927 if ((z != OBJ_SHIP) && (z != OBJ_START)){
2928 return internal_error("Object should be a ship, but isn't");
2931 if (fred_check_sexp(Ships[i].arrival_cue, OPR_BOOL, "arrival cue of ship \"%s\"", Ships[i].ship_name)){
2935 if (fred_check_sexp(Ships[i].departure_cue, OPR_BOOL, "departure cue of ship \"%s\"", Ships[i].ship_name)){
2939 if (Ships[i].arrival_location != ARRIVE_AT_LOCATION) {
2940 if (Ships[i].arrival_anchor < 0){
2941 if (error("Ship \"%s\" requires a valid arrival target", Ships[i].ship_name)){
2947 if (Ships[i].departure_location != DEPART_AT_LOCATION) {
2948 if (Ships[i].departure_anchor < 0){
2949 if (error("Ship \"%s\" requires a valid departure target", Ships[i].ship_name)){
2955 ai = Ships[i].ai_index;
2956 if (ai < 0 || ai >= MAX_AI_INFO){
2957 return internal_error("AI index out of range for ship \"%s\"", Ships[i].ship_name);
2960 if (Ai_info[ai].shipnum != i){
2961 return internal_error("AI/ship references are corrupt");
2964 if ((str = error_check_initial_orders(Ai_info[ai].goals, i, -1))>0) {
2966 return internal_error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str + 1);
2967 else if (*str == '!')
2969 else if (error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str))
2973 obj = Ai_info[ai].dock_objnum;
2975 if (!query_valid_object(obj)){
2976 return internal_error("Ship \"%s\" initially docked with non-existant ship", Ships[i].ship_name);
2979 if (Objects[obj].type != OBJ_SHIP && Objects[obj].type != OBJ_START){
2980 return internal_error("Ship \"%s\" initially docked with non-ship object", Ships[i].ship_name);
2983 ship = get_ship_from_obj(obj);
2984 if (!ship_docking_valid(i, ship) && !ship_docking_valid(ship, i)){
2985 return internal_error("Docking illegal between \"%s\" and \"%s\" (initially docked)", Ships[i].ship_name, Ships[ship].ship_name);
2988 z = get_docking_list(Ships[i].modelnum);
2989 point = Ai_info[ai].dock_index;
2990 if (point < 0 || point >= z){
2991 internal_error("Invalid docker point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
2994 z = get_docking_list(Ships[ship].modelnum);
2995 point = Ai_info[ai].dockee_index;
2996 if (point < 0 || point >= z){
2997 internal_error("Invalid dockee point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
3003 if (count != ship_get_num_ships()){
3004 return internal_error("num_ships is incorrect");
3008 for (i=0; i<MAX_WINGS; i++) {
3010 j = Wings[i].wave_count;
3011 if (j) { // is wing being used?
3013 if (j < 0 || j > MAX_SHIPS_PER_WING){
3014 return internal_error("Invalid number of ships in wing \"%s\"", Wings[i].name);
3018 obj = wing_objects[i][j];
3019 if (obj < 0 || obj >= MAX_OBJECTS){
3020 return internal_error("Wing_objects has an illegal object index");
3023 if (!query_valid_object(obj)){
3024 return internal_error("Wing_objects references an unused object");
3027 // Now, at this point, we can assume several things. We have a valid object because
3028 // we passed query_valid_object(), and all valid objects were already checked above,
3029 // so this object has valid information, such as the instance.
3031 if ((Objects[obj].type == OBJ_SHIP) || (Objects[obj].type == OBJ_START)) {
3032 ship = Objects[obj].instance;
3033 sprintf(buf, "%s %d", Wings[i].name, j + 1);
3034 if (stricmp(buf, Ships[ship].ship_name)){
3035 return internal_error("Ship \"%s\" in wing should be called \"%s\"", Ships[ship].ship_name, buf);
3038 switch (ship_query_general_type(ship))
3040 case SHIP_TYPE_FIGHTER_BOMBER:
3041 case SHIP_TYPE_CRUISER:
3042 case SHIP_TYPE_AWACS:
3043 case SHIP_TYPE_GAS_MINER:
3044 case SHIP_TYPE_CORVETTE:
3045 case SHIP_TYPE_FREIGHTER:
3046 case SHIP_TYPE_CAPITAL:
3047 case SHIP_TYPE_TRANSPORT:
3048 case SHIP_TYPE_SUPERCAP:
3052 if (error("Ship \"%s\" is an illegal type to be in a wing", Ships[ship].ship_name)){
3057 return internal_error("Wing_objects of \"%s\" references an illegal object type", Wings[i].name);
3060 if (Ships[ship].wingnum != i){
3061 return internal_error("Wing/ship references are corrupt");
3064 if (ship != Wings[i].ship_index[j]){
3065 return internal_error("Ship/wing references are corrupt");
3069 team = Ships[ship].team;
3070 } else if (team != Ships[ship].team && team < 999){
3071 if (error("ship teams mixed within same wing (\"%s\")", Wings[i].name)){
3077 if ((Wings[i].special_ship < 0) || (Wings[i].special_ship >= Wings[i].wave_count)){
3078 return internal_error("Special ship out of range for \"%s\"", Wings[i].name);
3081 if (Wings[i].num_waves < 0){
3082 return internal_error("Number of waves for \"%s\" is negative", Wings[i].name);
3085 if ((Wings[i].threshold < 0) || (Wings[i].threshold >= Wings[i].wave_count)){
3086 return internal_error("Threshold for \"%s\" is invalid", Wings[i].name);
3089 if (Wings[i].threshold + Wings[i].wave_count > MAX_SHIPS_PER_WING) {
3090 Wings[i].threshold = MAX_SHIPS_PER_WING - Wings[i].wave_count;
3091 if(error("Threshold for wing \"%s\" is higher than allowed. Reset to %d", Wings[i].name, Wings[i].threshold)){
3096 for (j=0; j<obj_count; j++){
3098 if (!stricmp(names[j], Wings[i].name)){
3099 return internal_error("Wing name is also used by an object (%s)", names[j]);
3104 if(fred_check_sexp(Wings[i].arrival_cue, OPR_BOOL, "arrival cue of wing \"%s\"", Wings[i].name)){
3108 if(fred_check_sexp(Wings[i].departure_cue, OPR_BOOL, "departure cue of wing \"%s\"", Wings[i].name)){
3112 if (Wings[i].arrival_location != ARRIVE_AT_LOCATION) {
3113 if (Wings[i].arrival_anchor < 0)
3114 if (error("Wing \"%s\" requires a valid arrival target", Wings[i].name))
3118 if (Wings[i].departure_location != DEPART_AT_LOCATION) {
3119 if (Wings[i].departure_anchor < 0)
3120 if (error("Wing \"%s\" requires a valid departure target", Wings[i].name))
3124 if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i))>0) {
3126 return internal_error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str + 1);
3127 else if (*str == '!')
3129 else if (error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str))
3136 if (count != num_wings){
3137 return internal_error("num_wings is incorrect");
3140 for (i=0; i<Num_waypoint_lists; i++) {
3141 for (z=0; z<obj_count; z++){
3143 if (!stricmp(names[z], Waypoint_lists[i].name)){
3144 return internal_error("Waypoint path name is also used by an object (%s)", names[z]);
3149 j = Waypoint_lists[i].count;
3151 sprintf(buf, "%s:%d", Waypoint_lists[i].name, j + 1);
3152 for (z=0; z<obj_count; z++){
3154 if (!stricmp(names[z], buf)){
3160 if (z == obj_count){
3161 return internal_error("Waypoint \"%s\" not linked to an object", buf);
3166 if (Player_starts > MAX_PLAYERS){
3167 return internal_error("Number of player starts exceeds max limit");
3170 if (!multi && (Player_starts > 1)){
3171 if (error("Multiple player starts exist, but this is a single player mission")){
3176 if (Num_reinforcements > MAX_REINFORCEMENTS){
3177 return internal_error("Number of reinforcements exceeds max limit");
3180 for (i=0; i<Num_reinforcements; i++) {
3182 for (ship=0; ship<MAX_SHIPS; ship++){
3183 if ((Ships[ship].objnum >= 0) && !stricmp(Ships[ship].ship_name, Reinforcements[i].name)) {
3189 for (wing=0; wing<MAX_WINGS; wing++){
3190 if (Wings[wing].wave_count && !stricmp(Wings[wing].name, Reinforcements[i].name)) {
3197 return internal_error("Reinforcement name not found in ships or wings");
3201 /* for (i=0; i<num_messages; i++) {
3202 if (Messages[i].num_times < 0)
3203 return internal_error("Number of times to play message is negative");
3205 z = Messages[i].who_from;
3206 if (z < -1 || z >= MAX_SHIPS) // hacked! -1 should be illegal..
3207 return internal_error("Message originator index is out of range");
3209 if (Ships[z].objnum == -1)
3210 return internal_error("Message originator points to nonexistant ship");
3212 if (fred_check_sexp(Messages[i].sexp, OPR_BOOL,
3213 "Message formula from \"%s\"", Ships[Messages[i].who_from].ship_name))
3217 SDL_assert((Player_start_shipnum >= 0) && (Player_start_shipnum < MAX_SHIPS) && (Ships[Player_start_shipnum].objnum >= 0));
3218 i = global_error_check_player_wings(multi);
3223 for (i=0; i<Num_mission_events; i++){
3224 if (fred_check_sexp(Mission_events[i].formula, OPR_NULL, "mission event \"%s\"", Mission_events[i].name)){
3229 for (i=0; i<Num_goals; i++){
3230 if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission goal \"%s\"", Mission_goals[i].name)){
3235 for ( bs = 0; bs < Num_teams; bs++ ) {
3236 for (s=0; s<Briefings[bs].num_stages; s++) {
3237 sp = &Briefings[bs].stages[s];
3239 for (i=0; i<t-1; i++){
3240 for (j=i+1; j<t; j++) {
3241 if ((sp->icons[i].id > 0) && (sp->icons[i].id == sp->icons[j].id)){
3242 if (error("Duplicate icon IDs %d in briefing stage %d", sp->icons[i].id, s + 1)){
3251 for ( j = 0; j < Num_teams; j++ ) {
3252 for (i=0; i<Debriefings[j].num_stages; i++) {
3253 if (fred_check_sexp(Debriefings[j].stages[i].formula, OPR_BOOL, "debriefing stage %d", i + 1)){
3259 // for all wings, be sure that the orders accepted for all ships are the same for all ships
3261 starting_orders = -1;
3262 for (i=0; i<MAX_WINGS; i++) {
3263 int default_orders, starting_wing;
3265 if ( !Wings[i].wave_count ){
3269 // determine if this wing is a starting wing of the player
3271 for ( j = 0; j < MAX_STARTING_WINGS; j++ ) {
3272 if ( !stricmp( Wings[i].name, Starting_wing_names[j]) ){
3276 if ( j == MAX_STARTING_WINGS ){
3280 // first, be sure this isn't a reinforcement wing.
3281 if ( starting_wing && (Wings[i].flags & WF_REINFORCEMENT) ) {
3282 if ( error("Starting Wing %s marked as reinforcement. This wing\nshould either be renamed, or unmarked as reinforcement.", Wings[i].name) ){
3288 for ( j = 0; j < Wings[i].wave_count; j++ ) {
3291 orders = Ships[Wings[i].ship_index[j]].orders_accepted;
3293 default_orders = orders;
3294 } else if ( default_orders != orders ) {
3295 if (error("Wing %s has ships with different player orders which\nare ignored. They must all be the same", Wings[i].name ) ){
3301 // make sure that these ignored orders are the same for all starting wings of the player
3302 if ( starting_wing ) {
3303 if ( starting_orders == -1 ) {
3304 starting_orders = default_orders;
3306 if ( starting_orders != default_orders ) {
3307 if ( error("Player starting wing %s has orders which don't match other starting wings\n", Wings[i].name) ){
3315 if (Num_jump_nodes < 0 || Num_jump_nodes > MAX_JUMP_NODES){
3316 return internal_error("Jump node count is illegal");
3319 fred_check_message_personas();
3324 int CFREDView::global_error_check_mixed_player_wing(int w)
3326 int i, s, species = -1, mixed = 0;
3328 for (i=0; i<Wings[w].wave_count; i++) {
3329 s = Wings[w].ship_index[i];
3331 species = Ship_info[Ships[s].ship_info_index].species;
3332 else if (Ship_info[Ships[s].ship_info_index].species != species)
3337 if (error("%s wing must all be of the same species", Wings[w].name))
3343 int CFREDView::global_error_check_player_wings(int multi)
3345 int i, z, alpha, beta, gamma, zeta, err, alpha_count, zeta_count;
3348 z = Ships[Player_start_shipnum].wingnum;
3349 alpha = wing_name_lookup("alpha", 1);
3350 beta = wing_name_lookup("beta", 1);
3351 gamma = wing_name_lookup("gamma", 1);
3352 zeta = wing_name_lookup( "zeta", 1 );
3355 free_sexp2(Wings[alpha].arrival_cue);
3356 Wings[alpha].arrival_cue = Locked_sexp_true;
3359 if (multi && (alpha < 0)){
3360 if (error("Alpha wing is required for multiplayer missions")){
3365 // Check to be sure that any player starting wing doesn't have > 1 wave for multiplayer
3367 if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
3368 if ( alpha && (Wings[alpha].num_waves > 1) ) {
3369 error("Alpha wing must contain only 1 wave.\nThis change has been made for you.");
3370 Wings[alpha].num_waves = 1;
3373 if ( zeta && (Wings[zeta].num_waves > 1) ) {
3374 error("Zeta wing must contain only 1 wave.\nThis change has been made for you.");
3375 Wings[zeta].num_waves = 1;
3380 if ( alpha && (Wings[alpha].num_waves > 1) ) {
3381 error("Alpha wing must contain only 1 wave.\nThis change has been made for you.");
3382 Wings[alpha].num_waves = 1;
3385 if ( beta && (Wings[beta].num_waves > 1) ) {
3386 error("Beta wing must contain only 1 wave.\nThis change has been made for you.");
3387 Wings[beta].num_waves = 1;
3390 if ( gamma && (Wings[gamma].num_waves > 1) ) {
3391 error("Gamma wing must contain only 1 wave.\nThis change has been made for you.");
3392 Wings[gamma].num_waves = 1;
3398 // if not a multiplayer misison, or a coop multiplayer mission, then do "normal"
3399 // wing name checking.
3400 if ( !multi || (The_mission.game_type & MISSION_TYPE_MULTI_COOP) ) {
3401 if (((alpha >= 0) || (z >= 0)) && (alpha != z)){
3402 if (error("Player start is not in Alpha wing")){
3407 if ((beta >= 0) && (alpha < 0)){
3408 if (error("Alpha wing required, but not present")){
3413 if ((gamma >= 0) && (beta < 0)){
3414 if (error("Beta wing required, but not present")){
3419 if ((alpha >= 0) && (Wings[alpha].wave_count > 4)){
3420 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3425 if ((beta >= 0) && (Wings[beta].wave_count > 4)){
3426 if (error("Beta wing has too many ships. Should only have 4 max.")){
3431 if ((gamma >= 0) && (Wings[gamma].wave_count > 4)){
3432 if (error("Gamma wing has too many ships. Should only have 4 max.")){
3437 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3438 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3442 } else if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
3444 if (error("Zeta wing is required for multiplayer team vs. team missions")){
3449 if ( Wings[alpha].wave_count > 4 ){
3450 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3455 if ( Wings[zeta].wave_count > 4 ) {
3456 if (error("Zeta wing has too many ships. Should only have 4 max.")){
3461 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3462 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3467 if ((zeta >= 0) && Wings[zeta].arrival_delay){
3468 if (error("Zeta wing shouldn't have a non-zero arrival delay")){
3472 } else if ( The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT ) {
3473 if ( Wings[alpha].wave_count > 4 ) {
3474 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3479 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3480 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3485 error("Unknown game type: %d", The_mission.game_type);
3491 if (global_error_check_mixed_player_wing(alpha)){
3497 if (global_error_check_mixed_player_wing(beta)){
3503 if (global_error_check_mixed_player_wing(gamma)){
3509 if (global_error_check_mixed_player_wing(zeta)){
3515 alpha_count = zeta_count = 0;
3516 ptr = GET_FIRST(&obj_used_list);
3517 while (ptr != END_OF_LIST(&obj_used_list)) {
3520 if (ptr->type == OBJ_START) {
3521 z = Ships[i].wingnum;
3527 } else if (z == zeta){
3531 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) {
3532 if ((z != alpha) && (z != zeta)){
3536 if ((z != alpha) && (z != beta) && (z != gamma)){
3543 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) {
3544 if (error("Player \"%s\" should be part Alpha or Zeta wing", Ships[i].ship_name)){
3548 if (error("Player \"%s\" should be part Alpha, Beta or Gamma wing", Ships[i].ship_name)){
3555 ptr = GET_NEXT(ptr);
3558 if ((alpha >= 0) && !alpha_count){
3559 if (error("Alpha wing doesn't contain any players, which it should.")){
3564 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS){
3565 if ((zeta >= 0) && !zeta_count){
3566 if (error("Zeta wing doesn't contain any players, which it should.")){
3575 int CFREDView::error(char *msg, ...)
3580 va_start(args, msg);
3581 vsprintf(buf, msg, args);
3585 if (MessageBox(buf, "Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
3591 int CFREDView::internal_error(char *msg, ...)
3596 va_start(args, msg);
3597 vsprintf(buf, msg, args);
3605 sprintf(buf2, "%s\n\nThis is an internal error. Please let Jason\n"
3606 "know about this so he can fix it. Click cancel to debug.", buf);
3608 if (MessageBox(buf2, "Internal Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
3609 Int3(); // drop to debugger so the problem can be analyzed.
3612 MessageBox(buf, "Error", MB_OK | MB_ICONEXCLAMATION);
3618 int CFREDView::fred_check_sexp(int sexp, int type, char *msg, ...)
3620 char buf[512], buf2[2048], buf3[4096];
3621 int err = 0, z, faulty_node;
3624 va_start(args, msg);
3625 vsprintf(buf, msg, args);
3631 z = check_sexp_syntax(sexp, type, 1, &faulty_node);
3635 convert_sexp_to_string(sexp, buf2, SEXP_ERROR_CHECK_MODE);
3636 sprintf(buf3, "Error in %s: %s\n\nIn sexpression: %s\n(Error appears to be: %s)",
3637 buf, sexp_error_message(z), buf2, Sexp_nodes[faulty_node].text);
3639 if (z < 0 && z > -100)
3643 return internal_error(buf3);
3651 void CFREDView::OnEditorsWaypoint()
3655 SDL_assert(Waypoint_editor_dialog.GetSafeHwnd());
3656 if (!Show_sexp_help)
3657 adjust = -SEXP_HELP_BOX_SIZE;
3659 if (!theApp.init_window(&Waypoint_wnd_data, &Waypoint_editor_dialog))
3662 Waypoint_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
3663 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
3664 Waypoint_editor_dialog.ShowWindow(SW_RESTORE);
3667 char *error_check_initial_orders(ai_goal *goals, int ship, int wing)
3670 int i, j, num, flag, found, inst, team, team2;
3674 source = Ships[ship].ship_name;
3675 team = Ships[ship].team;
3676 for (i=0; i<MAX_AI_GOALS; i++)
3677 if (!ai_query_goal_valid(ship, goals[i].ai_mode)) {
3678 if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode), source))
3683 SDL_assert(wing >= 0);
3684 SDL_assert(Wings[wing].wave_count > 0);
3685 source = Wings[wing].name;
3686 team = Ships[Objects[wing_objects[wing][0]].instance].team;
3687 for (j=0; j<Wings[wing].wave_count; j++)
3688 for (i=0; i<MAX_AI_GOALS; i++)
3689 if (!ai_query_goal_valid(Wings[wing].ship_index[j], goals[i].ai_mode)) {
3690 if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode),
3691 Ships[Wings[wing].ship_index[j]].ship_name))
3696 for (i=0; i<MAX_AI_GOALS; i++) {
3697 switch (goals[i].ai_mode) {
3699 case AI_GOAL_CHASE_ANY:
3700 case AI_GOAL_UNDOCK:
3701 case AI_GOAL_KEEP_SAFE_DISTANCE:
3702 case AI_GOAL_PLAY_DEAD:
3707 case AI_GOAL_WAYPOINTS:
3708 case AI_GOAL_WAYPOINTS_ONCE:
3714 return "Wings can't dock";
3717 case AI_GOAL_DESTROY_SUBSYSTEM:
3720 case AI_GOAL_DISARM_SHIP:
3721 case AI_GOAL_DISABLE_SHIP:
3722 case AI_GOAL_EVADE_SHIP:
3723 case AI_GOAL_STAY_NEAR_SHIP:
3724 case AI_GOAL_IGNORE:
3728 case AI_GOAL_CHASE_WING:
3729 case AI_GOAL_GUARD_WING:
3733 case AI_GOAL_STAY_STILL:
3738 return "*Invalid goal type";
3743 if (*goals[i].ship_name == '<')
3744 return "Invalid target";
3746 if (!stricmp(goals[i].ship_name, source))
3748 return "Target of ship's goal is itself";
3750 return "Target of wing's goal is itself";
3754 if (flag == 1) { // target waypoint required
3755 for (j=0; j<Num_waypoint_lists; j++)
3756 if (!stricmp(goals[i].ship_name, Waypoint_lists[j].name))
3760 return "*Invalid target waypoint path name";
3762 } else if (flag == 2) { // target ship required
3763 ptr = GET_FIRST(&obj_used_list);
3764 while (ptr != END_OF_LIST(&obj_used_list)) {
3765 if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3766 inst = ptr->instance;
3767 if (!stricmp(goals[i].ship_name, Ships[inst].ship_name)) {
3773 ptr = GET_NEXT(ptr);
3777 return "*Invalid target ship name";
3779 if (wing >= 0) { // check if target ship is in wing
3780 if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3781 return "Target ship of wing's goal is within said wing";
3784 team2 = Ships[inst].team;
3786 } else if (flag == 3) { // target wing required
3787 for (j=0; j<MAX_WINGS; j++)
3788 if (Wings[j].wave_count && !stricmp(Wings[j].name, goals[i].ship_name))
3792 return "*Invalid target wing name";
3794 if (ship >= 0) { // check if ship is in target wing
3795 if (Ships[ship].wingnum == j)
3796 return "Target wing of ship's goal is same wing said ship is part of";
3799 team2 = Ships[Objects[wing_objects[j][0]].instance].team;
3801 } else if (flag == 4) {
3802 ptr = GET_FIRST(&obj_used_list);
3803 while (ptr != END_OF_LIST(&obj_used_list)) {
3804 if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3805 inst = ptr->instance;
3806 if (!stricmp(goals[i].ship_name, Ships[inst].ship_name)) {
3811 } else if (ptr->type == OBJ_WAYPOINT) {
3812 if (!stricmp(goals[i].ship_name, object_name(OBJ_INDEX(ptr)))) {
3818 ptr = GET_NEXT(ptr);
3822 return "*Invalid target ship or waypoint name";
3825 if (wing >= 0) { // check if target ship is in wing
3826 if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3827 return "Target ship of wing's goal is within said wing";
3830 team2 = Ships[inst].team;
3834 switch (goals[i].ai_mode) {
3835 case AI_GOAL_DESTROY_SUBSYSTEM:
3836 SDL_assert(flag == 2 && inst >= 0);
3837 if (ship_get_subsys_index(&Ships[inst], goals[i].docker.name, 1) < 0)
3838 return "Unknown subsystem type";
3842 case AI_GOAL_DOCK: {
3843 int dock1 = -1, dock2 = -1, model1, model2;
3845 SDL_assert(flag == 2 && inst >= 0);
3846 if (!ship_docking_valid(ship, inst))
3847 return "Docking illegal between given ship types";
3849 model1 = Ships[ship].modelnum;
3850 num = get_docking_list(model1);
3851 for (j=0; j<num; j++) {
3852 SDL_assert(Docking_bay_list[j]);
3853 if (!stricmp(goals[i].docker.name, Docking_bay_list[j])) {
3859 model2 = Ships[inst].modelnum;
3860 num = get_docking_list(model2);
3861 for (j=0; j<num; j++) {
3862 SDL_assert(Docking_bay_list[j]);
3863 if (!stricmp(goals[i].dockee.name, Docking_bay_list[j])) {
3870 return "Invalid docker point";
3873 return "Invalid dockee point";
3875 if ((dock1 >= 0) && (dock2 >= 0)) {
3876 if ( !(model_get_dock_index_type(model1, dock1) & model_get_dock_index_type(model2, dock2)) )
3877 return "Dock points are incompatible";
3884 switch (goals[i].ai_mode) {
3886 case AI_GOAL_GUARD_WING:
3887 // if ((team == TEAM_HOSTILE && team2 == TEAM_FRIENDLY) || (team == TEAM_FRIENDLY && team2 == TEAM_HOSTILE)) {
3888 if (team != team2) { // MK, added support for TEAM_NEUTRAL. Won't this work?
3890 return "Ship assigned to guard opposite team";
3892 return "Wing assigned to guard opposite team";
3898 case AI_GOAL_CHASE_WING:
3899 case AI_GOAL_DESTROY_SUBSYSTEM:
3900 case AI_GOAL_DISARM_SHIP:
3901 case AI_GOAL_DISABLE_SHIP:
3902 if (team == team2) {
3904 return "Ship assigned to attack same team";
3906 return "Wings assigned to attack same team";
3916 // function (which is called externally from message editor and event editor) so skip through
3917 // the sexpression nodes to look for send-message commands to try to associate message personas
3919 void fred_check_message_personas()
3922 int i, op, j, ship_index;
3923 char *mname, *who_from;
3926 // this function is responsible for assigning personas to ships as well as error checking them.
3927 // clear out the persona index on all ship objects
3928 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3929 if ( objp->type == OBJ_SHIP ) {
3930 Ships[objp->instance].persona_index = -1;
3935 for (i = 0; i < MAX_SEXP_NODES; i++ ) {
3936 if ( Sexp_nodes[i].type == SEXP_NOT_USED )
3939 // look for only operator nodes
3940 if ( Sexp_nodes[i].subtype != SEXP_ATOM_OPERATOR )
3943 // now look for the send-message opeator
3944 op = find_operator( Sexp_nodes[i].text );
3945 if ( op != OP_SEND_MESSAGE )
3948 // have the message. parse through the message to determine who is sending the message.
3949 who_from = CTEXT(CDR(i));
3951 // we can ignore messages from any wingman, and allied, or from God.
3952 if ( !stricmp(who_from, "<Any wingman>") || !stricmp(who_from, "<Any allied>") || (who_from[0] == '#') )
3955 mname = CTEXT(CDR(CDR(CDR(i))));
3957 // check to see if who_from is a wing. Don't do processing if so.
3958 if ( wing_name_lookup(who_from, 1) != -1 )
3961 ship_index = ship_name_lookup( who_from );
3962 if ( ship_index == -1 ) {
3963 Int3(); // get allender. something funny is up with shipnames in send-message
3967 for ( j = Num_builtin_messages; j < Num_messages; j++ ) {
3968 if ( !stricmp(mname, Messages[j].name) ) {
3970 // check to see if there is a persona for this message -- if not, bail
3971 if ( Messages[j].persona_index == -1 )
3974 // if a ship isn't assigned a persona, and this message says that he is, assign it, and move on
3975 if ( Ships[ship_index].persona_index == -1 ) {
3976 Ships[ship_index].persona_index = Messages[j].persona_index;
3980 // we must be sure of the following conditions:
3981 // 1) a ship isn't assigned > 1 persona
3983 if ( Ships[ship_index].persona_index != Messages[j].persona_index )
3984 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 );
3989 // check that two or more ships are not using the same persona
3990 for (i = 0; i < Num_personas; i++ ) {
3994 // move through object list looking for number of shis using this persona
3996 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3997 if ( objp->type != OBJ_SHIP )
3999 if (Ships[objp->instance].persona_index == i )
4003 if ( persona_count > 1 )
4004 Fred_view_wnd->error("Persona %s used by more than 1 ship", Personas[Messages[j].persona_index].name );
4010 void CFREDView::OnViewOutlines()
4012 Show_outlines = !Show_outlines;
4013 theApp.write_ini_file();
4017 void CFREDView::OnUpdateViewOutlines(CCmdUI* pCmdUI)
4019 pCmdUI->SetCheck(Show_outlines);
4022 void CFREDView::OnUpdateNewShipType(CCmdUI* pCmdUI)
4027 z = m_new_ship_type_combo_box.GetCurSelNEW();
4029 m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
4031 cur_model_index = z;
4033 bar = GetDlgItem(pCmdUI->m_nID);
4035 pCmdUI -> ContinueRouting();
4036 return; // not for us
4039 pCmdUI -> SetCheck((bar->GetStyle() & WS_VISIBLE) != 0);
4042 void CFREDView::OnShowStarfield()
4044 Show_stars = !Show_stars;
4045 theApp.write_ini_file();
4049 void CFREDView::OnUpdateShowStarfield(CCmdUI* pCmdUI)
4051 pCmdUI->SetCheck(Show_stars);
4054 void CFREDView::OnAsteroidEditor()
4056 asteroid_editor dlg;
4061 void CFREDView::OnRunFreespace()
4065 PROCESS_INFORMATION pi;
4068 if (!FREDDoc_ptr->SaveModified())
4072 si.lpReserved = NULL;
4073 si.lpDesktop = NULL;
4077 si.lpReserved2 = NULL;
4079 r = CreateProcess("..\\..\\Fs.exe", NULL, NULL, NULL, FALSE, 0, NULL, "..\\..", &si, &pi);
4082 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
4085 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
4091 // Display the string.
4092 MessageBox(lpMsgBuf);
4095 LocalFree( lpMsgBuf );
4099 void CFREDView::OnEditorCampaign()
4101 if (!FREDDoc_ptr->SaveModified())
4104 SDL_assert(!Campaign_wnd);
4105 Campaign_wnd = new campaign_tree_wnd;
4106 if (Campaign_wnd->Create(NULL, "Campaign Editor", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
4107 CFrameWnd::rectDefault, NULL, "IDR_MENU_CAMPAIGN")) {
4108 Campaign_wnd->ShowWindow(SW_SHOW);
4109 Campaign_wnd->UpdateWindow();
4113 void CFREDView::OnShowShips()
4115 Show_ships = !Show_ships;
4120 void CFREDView::OnUpdateShowShips(CCmdUI* pCmdUI)
4122 pCmdUI->SetCheck(Show_ships);
4125 void CFREDView::OnShowStarts()
4127 Show_starts = !Show_starts;
4132 void CFREDView::OnUpdateShowStarts(CCmdUI* pCmdUI)
4134 pCmdUI->SetCheck(Show_starts);
4137 void CFREDView::OnShowFriendly()
4139 Show_friendly = !Show_friendly;
4144 void CFREDView::OnUpdateShowFriendly(CCmdUI* pCmdUI)
4146 pCmdUI->SetCheck(Show_friendly);
4149 void CFREDView::OnShowHostile()
4151 Show_hostile = !Show_hostile;
4156 void CFREDView::OnUpdateShowHostile(CCmdUI* pCmdUI)
4158 pCmdUI->SetCheck(Show_hostile);
4161 void CFREDView::OnToggleViewpoint()
4163 if (viewpoint || !query_valid_object())
4168 view_obj = cur_object_index;
4174 void CFREDView::OnRevert()
4176 if (!FREDDoc_ptr->SaveModified())
4179 FREDDoc_ptr->DeleteContents();
4180 FREDDoc_ptr->OnOpenDocument(NULL);
4183 void CFREDView::OnUpdateRevert(CCmdUI* pCmdUI)
4185 pCmdUI->Enable(*Mission_filename);
4188 BOOL CFREDView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
4190 if ((Cursor_over >= 0) || Selection_lock) {
4191 if (Editing_mode == 1) {
4192 SetCursor(h_cursor_move);
4195 } else if (Editing_mode == 2) {
4196 SetCursor(h_cursor_rotate);
4201 return CView::OnSetCursor(pWnd, nHitTest, message);
4204 void CFREDView::OnHideObjects()
4208 ptr = GET_FIRST(&obj_used_list);
4209 while (ptr != END_OF_LIST(&obj_used_list)) {
4210 if (ptr->flags & OF_MARKED) {
4211 ptr->flags |= OF_HIDDEN;
4212 unmark_object(OBJ_INDEX(ptr));
4215 ptr = GET_NEXT(ptr);
4219 void CFREDView::OnShowHiddenObjects()
4223 ptr = GET_FIRST(&obj_used_list);
4224 while (ptr != END_OF_LIST(&obj_used_list)) {
4225 ptr->flags &= ~OF_HIDDEN;
4226 ptr = GET_NEXT(ptr);
4232 void CFREDView::OnEditUndo()
4235 matrix viewer_orient;
4237 if (Undo_available) {
4238 viewer_pos = view_pos;
4239 viewer_orient = view_orient;
4240 FREDDoc_ptr->autoload();
4241 view_pos = viewer_pos;
4242 view_orient = viewer_orient;
4246 void CFREDView::OnUpdateEditUndo(CCmdUI* pCmdUI)
4248 pCmdUI->Enable(Undo_available);
4251 void CFREDView::OnEditorsBriefing()
4253 if (!Briefing_dialog) {
4254 Briefing_dialog = new briefing_editor_dlg;
4255 Briefing_dialog->create();
4258 Briefing_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
4259 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
4260 Briefing_dialog->ShowWindow(SW_RESTORE);
4263 void CFREDView::OnEditorsDebriefing()
4265 debriefing_editor_dlg dlg;
4270 void CFREDView::OnSaveCamera()
4272 saved_cam_pos = view_pos;
4273 saved_cam_orient = view_orient;
4276 void CFREDView::OnRestoreCamera()
4278 view_pos = saved_cam_pos;
4279 view_orient = saved_cam_orient;
4283 void CFREDView::OnUpdateRestoreCamera(CCmdUI* pCmdUI)
4285 pCmdUI->Enable(!IS_VEC_NULL(&saved_cam_orient.fvec));
4288 void CFREDView::OnShowSexpHelp()
4292 Show_sexp_help = !Show_sexp_help;
4293 Ship_editor_dialog.show_hide_sexp_help();
4294 Wing_editor_dialog.show_hide_sexp_help();
4296 if (Event_editor_dlg) {
4297 Event_editor_dlg->GetWindowRect(rect);
4299 rect.bottom += SEXP_HELP_BOX_SIZE;
4301 rect.bottom -= SEXP_HELP_BOX_SIZE;
4303 Event_editor_dlg->MoveWindow(rect);
4307 void CFREDView::OnUpdateShowSexpHelp(CCmdUI* pCmdUI)
4309 pCmdUI->SetCheck(Show_sexp_help);
4312 void CFREDView::OnLookatObj()
4314 Lookat_mode = !Lookat_mode;
4315 if (Lookat_mode && query_valid_object()) {
4319 loc = Objects[cur_object_index].pos;
4320 vm_vec_sub(&v, &loc, &view_pos);
4322 if (v.x || v.y || v.z) {
4323 vm_vector_2_matrix(&m, &v, NULL, NULL);
4329 void CFREDView::OnUpdateLookatObj(CCmdUI* pCmdUI)
4331 pCmdUI->SetCheck(Lookat_mode);
4334 void CFREDView::OnGroup(UINT nID)
4336 int n = 1 << (nID - ID_GROUP1);
4340 objp = GET_FIRST(&obj_used_list);
4341 while (objp != END_OF_LIST(&obj_used_list)) {
4342 if (objp->type == OBJ_SHIP) {
4343 if (Ships[objp->instance].group & n)
4344 mark_object(OBJ_INDEX(objp));
4347 objp = GET_NEXT(objp);
4353 void CFREDView::OnSetGroup(UINT nID)
4355 int i, err = 0, n = 1 << (nID - ID_SET_GROUP1);
4358 for (i=0; i<MAX_SHIPS; i++)
4359 Ships[i].group &= ~n;
4361 objp = GET_FIRST(&obj_used_list);
4362 while (objp != END_OF_LIST(&obj_used_list)) {
4363 if (objp->flags & OF_MARKED) {
4364 if (objp->type == OBJ_SHIP) {
4365 Ships[objp->instance].group |= n;
4371 objp = GET_NEXT(objp);
4375 Fred_main_wnd->MessageBox("Only ships can be in groups, and not players or waypoints, etc.\n"
4376 "These illegal objects you marked were not placed in the group");
4381 void CFREDView::OnInitialUpdate()
4383 char *ptr, text[512];
4385 CView::OnInitialUpdate();
4387 // check the time/checksum strings.
4390 if ( memcmp(ptr, DEFAULT_CHECKSUM_STRING, strlen(DEFAULT_CHECKSUM_STRING)) ) {
4391 int stamped_checksum, checksum;
4393 // the checksum is not the default checksum. Calculate the checksum of the string
4395 memcpy(&stamped_checksum, ptr, sizeof(stamped_checksum) );
4397 ptr += 8; // get us to the actual string to calculate the checksum
4398 CALCULATE_STAMP_CHECKSUM();
4400 if ( checksum != stamped_checksum ){
4401 expire_game = EXPIRE_BAD_CHECKSUM;
4404 // now check the time
4407 if ( memcmp( ptr, DEFAULT_TIME_STRING, strlen(DEFAULT_TIME_STRING)) ) {
4408 int expire_time, current_time;
4410 // not the default time -- check against the current time
4411 memcpy( &expire_time, ptr, sizeof(expire_time) );
4412 time( (long *)¤t_time );
4413 if ( current_time > expire_time )
4414 expire_game = EXPIRE_BAD_TIME;
4417 // since the default checksum has changed -- put up a message which shows who the program
4421 sprintf(text, "This version of Fred has been compiled for %s", ptr);
4422 MessageBox(text, NULL, MB_OK);
4425 SetTimer(1, FRED_EXPIRE_TIME, expire_game_proc);
4429 void CFREDView::OnEditorsAdjustGrid()
4431 adjust_grid_dlg dlg;
4437 void CFREDView::OnEditorsShieldSys()
4444 void CFREDView::OnLevelObj()
4450 void CFREDView::OnAlignObj()
4452 verticalize_controlled();
4456 void CFREDView::OnControlObj()
4458 Control_mode = (Control_mode + 1) % 2;
4461 void CFREDView::OnNextObj()
4465 if (Bg_bitmap_dialog) {
4466 if (Cur_bitmap == -1)
4468 if (Num_starfield_bitmaps)
4471 Bg_bitmap_dialog -> update_data();
4478 if (Cur_bitmap >= Num_starfield_bitmaps)
4481 Bg_bitmap_dialog -> update_data();
4485 if (EMPTY(&obj_used_list))
4488 if (query_valid_object()) {
4489 ptr = Objects[cur_object_index].next;
4490 if (ptr == END_OF_LIST(&obj_used_list))
4491 ptr = GET_NEXT(ptr);
4494 ptr = GET_FIRST(&obj_used_list);
4496 if (Marked > 1) { // cycle through marked list
4497 while (!(ptr->flags & OF_MARKED))
4499 ptr = GET_NEXT(ptr);
4500 if (ptr == END_OF_LIST(&obj_used_list))
4501 ptr = GET_NEXT(ptr);
4504 set_cur_object_index(OBJ_INDEX(ptr));
4508 unmark_object(cur_object_index);
4510 mark_object(OBJ_INDEX(ptr));
4514 void CFREDView::OnPrevObj()
4516 int arr[MAX_OBJECTS], i = 0, n = 0;
4519 if (Bg_bitmap_dialog) {
4520 if (Cur_bitmap == -1)
4522 if (Num_starfield_bitmaps)
4524 Cur_bitmap = Num_starfield_bitmaps - 1;
4525 Bg_bitmap_dialog -> update_data();
4533 Cur_bitmap = Num_starfield_bitmaps - 1;
4535 Bg_bitmap_dialog -> update_data();
4539 if (EMPTY(&obj_used_list))
4542 ptr = GET_FIRST(&obj_used_list);
4543 while (ptr != END_OF_LIST(&obj_used_list)) {
4544 if (cur_object_index == OBJ_INDEX(ptr))
4547 arr[n++] = OBJ_INDEX(ptr);
4548 ptr = GET_NEXT(ptr);
4552 if (query_valid_object()) {
4560 if (Marked > 1) { // cycle through marked list
4561 while (!(Objects[i].flags & OF_MARKED))
4568 set_cur_object_index(i);
4572 unmark_object(cur_object_index);
4578 void CFREDView::OnEditDelete()
4580 if (!button_down && Marked) {
4582 FREDDoc_ptr->autosave("object delete");
4585 Update_window = 2; // For some strange reason, need to redraw twice for it to take.
4588 void CFREDView::OnEditDeleteWing()
4590 if (!button_down && (cur_wing >= 0)) {
4592 FREDDoc_ptr->autosave("wing delete");
4595 Ship_editor_dialog.initialize_data(1);
4597 Wing_editor_dialog.initialize_data(1);
4600 Update_window = 2; // For some strange reason, need to redraw twice for it to take.
4603 void CFREDView::OnMarkWing()
4605 int i, wing = cur_wing;
4610 for (i=0; i<Wings[wing].wave_count; i++)
4611 mark_object(wing_objects[wing][i]);
4613 SDL_assert(Wings[wing].special_ship >= 0 && Wings[wing].special_ship < Wings[wing].wave_count);
4614 set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]);
4618 void CFREDView::OnUpdateControlObj(CCmdUI* pCmdUI)
4620 pCmdUI->SetCheck(Control_mode != 0);
4623 void CFREDView::OnAaGridlines()
4625 Aa_gridlines = !Aa_gridlines;
4628 void CFREDView::OnUpdateAaGridlines(CCmdUI* pCmdUI)
4630 pCmdUI->SetCheck(Aa_gridlines);
4634 void CFREDView::OnCmdBrief()
4642 void CFREDView::OnDisableUndo()
4644 Autosave_disabled = !Autosave_disabled;
4647 void CFREDView::OnUpdateDisableUndo(CCmdUI* pCmdUI)
4649 pCmdUI->SetCheck(Autosave_disabled);
4652 void CFREDView::OnUpdateCmdBrief(CCmdUI* pCmdUI)
4654 pCmdUI->Enable(!(The_mission.game_type & MISSION_TYPE_MULTI));
4657 int get_visible_sub_system_count(ship *shipp)
4660 ship_subsys *cur_subsys;
4662 for (cur_subsys = GET_FIRST(&shipp->subsys_list); cur_subsys != END_OF_LIST(&shipp->subsys_list); cur_subsys = GET_NEXT(cur_subsys)) {
4663 if (cur_subsys->system_info->subobj_num != -1) {
4671 int get_next_visible_subsys(ship *shipp, ship_subsys **next_subsys)
4673 int count = get_visible_sub_system_count(shipp);
4675 // return don't try to display
4681 if (*next_subsys == NULL) {
4682 *next_subsys = &shipp->subsys_list;
4686 for (*next_subsys = GET_NEXT(*next_subsys); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4687 if ((*next_subsys)->system_info->subobj_num != -1) {
4693 // look for first after wrap
4694 for (*next_subsys = GET_FIRST(&shipp->subsys_list); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4695 if ((*next_subsys)->system_info->subobj_num != -1) {
4701 Int3(); // should be impossible to miss
4705 int get_prev_visible_subsys(ship *shipp, ship_subsys **prev_subsys)
4707 int count = get_visible_sub_system_count(shipp);
4709 // return don't try to display
4715 SDL_assert(*prev_subsys != NULL);
4718 for (*prev_subsys = GET_PREV(*prev_subsys); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4719 if ((*prev_subsys)->system_info->subobj_num != -1) {
4725 // look for first after wrap
4726 for (*prev_subsys = GET_LAST(&shipp->subsys_list); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4727 if ((*prev_subsys)->system_info->subobj_num != -1) {
4733 Int3(); // should be impossible to miss
4737 // update next subsystem to view
4738 void CFREDView::OnNextSubsys()
4742 if (cur_object_index < 0) {
4746 objp = &Objects[cur_object_index];
4748 // check if cur object is ship type
4749 if (objp->type == OBJ_SHIP) {
4751 // check if same ship
4752 if (Render_subsys.ship_obj == objp) {
4754 // if already on, advance to next
4755 if (Render_subsys.do_render) {
4756 if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4766 // set up new and advance to first
4767 Render_subsys.do_render = true;
4768 Render_subsys.ship_obj = objp;
4769 if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4779 void CFREDView::OnPrevSubsys()
4781 if (!Render_subsys.do_render) {
4785 if ( (cur_object_index < 0) || (Objects[cur_object_index].type != OBJ_SHIP) || (&Objects[cur_object_index] != Render_subsys.ship_obj) ) {
4790 if ( !get_prev_visible_subsys(&Ships[Objects[cur_object_index].instance], &Render_subsys.cur_subsys) ) {
4796 void CFREDView::OnCancelSubsys()
4798 Render_subsys.do_render = false;
4799 Render_subsys.ship_obj = NULL;
4800 Render_subsys.cur_subsys = NULL;
4804 void CFREDView::OnShowPaths()
4806 Show_paths_fred = !Show_paths_fred;
4807 theApp.write_ini_file();
4811 void CFREDView::OnUpdateShowPaths(CCmdUI* pCmdUI)
4813 pCmdUI->SetCheck(Show_paths_fred);
4816 void CFREDView::OnShowDockPoints()
4818 Show_dock_points = !Show_dock_points;
4819 theApp.write_ini_file();
4823 void CFREDView::OnUpdateShowDockPoints(CCmdUI* pCmdUI)
4825 pCmdUI->SetCheck(Show_dock_points);
4828 void CFREDView::OnDumpStats()