2 * $Logfile: /Freespace2/code/Fred2/FREDView.cpp $
7 * View class for a document/view architechure design program, which we don't
8 * want or need, but MFC forces us to use. This is the main place we handle
9 * MFC messages, events, etc. Sort of the interface between our code and MFC.
10 * There is also a lot of our code in here related to these things.
13 * Revision 1.2 2002/05/07 03:16:44 theoddone33
14 * The Great Newline Fix
16 * Revision 1.1.1.1 2002/05/03 03:28:08 root
20 * 17 7/15/99 3:07p Dave
21 * 32 bit detection support. Mouse coord commandline.
23 * 16 7/09/99 5:54p Dave
24 * Seperated cruiser types into individual types. Added tons of new
25 * briefing icons. Campaign screen.
27 * 15 6/04/99 2:20p Andsager
28 * Add dump stats basic functionality
30 * 14 4/07/99 6:21p Dave
31 * Fred and Freespace support for multiple background bitmaps and suns.
32 * Fixed link errors on all subprojects. Moved encrypt_init() to
33 * cfile_init() and lcl_init(), since its safe to call twice.
35 * 13 3/26/99 4:49p Dave
36 * Made cruisers able to dock with stuff. Made docking points and paths
39 * 12 3/20/99 5:09p Dave
40 * Fixed release build fred warnings and unhandled exception.
42 * 11 3/04/99 11:56a Johnson
43 * Fixed an undo-rotation bug.
45 * 10 3/02/99 9:25p Dave
46 * Added a bunch of model rendering debug code. Started work on fixing
47 * beam weapon wacky firing.
49 * 9 3/01/99 10:00a Dave
50 * Fxied several dogfight related stats bugs.
52 * 8 2/23/99 2:32p Dave
53 * First run of oldschool dogfight mode.
55 * 7 1/27/99 4:09p Andsager
56 * Added highlight to ship subsystems
58 * 6 1/07/99 1:52p Andsager
59 * Initial check in of Sexp_variables
61 * 5 12/18/98 1:49a Dave
62 * Fixed Fred initialization problem resulting from hi-res mode changes.
64 * 4 10/13/98 9:27a Dave
65 * Started neatening up freespace.h
67 * 3 10/12/98 1:01p Dave
68 * Fixed object rotation bug (uninitialized data). Changed a few stubs to
69 * correspond to new var names.
71 * 2 10/07/98 6:28p Dave
72 * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
73 * Fred. Globalized mission and campaign file extensions. Removed Silent
74 * Threat specific code.
76 * 1 10/07/98 3:00p Dave
78 * 248 9/16/98 6:54p Dave
79 * Upped max sexpression nodes to 1800 (from 1600). Changed FRED to sort
80 * the ship list box. Added code so that tracker stats are not stored with
83 * 247 9/14/98 3:40p Allender
84 * better error checking for invalid number of waves for player wings in a
85 * multiplayer game. Better popup message in FreeSpace side.
87 * 246 6/18/98 4:28p Hoffoss
88 * Made invalid dock points in an initial order flag an error in Fred.
90 * 245 6/17/98 4:50p Hoffoss
91 * Added error checking for arrival delays used on wing player is in.
93 * 244 6/16/98 10:24a Hoffoss
94 * Switched internal errors over to normal looking errors for release
97 * 243 5/21/98 11:48a Hoffoss
98 * Removed check in and check out options.
100 * 242 5/21/98 12:58a Hoffoss
101 * Fixed warnings optimized build turned up.
103 * 241 5/19/98 1:19p Allender
104 * new low level reliable socket reading code. Make all missions/campaign
105 * load/save to data missions folder (i.e. we are rid of the player
108 * 240 5/14/98 5:31p Hoffoss
109 * Added some more error checking.
111 * 239 5/10/98 10:05p Allender
112 * only show cutscenes which have been seen before. Made Fred able to
113 * write missions anywhere, defaulting to player misison folder, not data
114 * mission folder. Fix FreeSpace code to properly read missions from
117 * 238 4/28/98 2:13p Hoffoss
118 * Added code to help keep invalid player ship types from existing in
121 * 237 4/26/98 6:05p Hoffoss
122 * Added multiplayer error checks requested by Dave B.
124 * 236 4/17/98 2:37p Duncan
125 * Added check to error checker for arrival/depature targets valid.
127 * 235 4/14/98 4:35p Hoffoss
128 * Fixed bug with launching FreeSpace from Fred. Current working
129 * directory wasn't being set properly.
131 * 234 4/14/98 3:38p Hoffoss
132 * Fixed the FreeSpace launch code in Fred.
134 * 233 4/07/98 9:42a Allender
135 * put in persona combo box into ship editor. Removed code to assign
136 * personas based on message
138 * 232 4/01/98 10:48a Hoffoss
139 * Changed Fred to not allow command briefings in multiplayer missions.
141 * 231 3/26/98 3:01p Hoffoss
142 * Put in check for alpha wing num ships < 4 for furball multiplayer
145 * 230 3/25/98 4:14p Hoffoss
146 * Split ship editor up into ship editor and a misc dialog, which tracks
149 * 229 3/23/98 4:04p Hoffoss
150 * Fixed dialog window initialization so it looks better at startup (they
151 * don't flash on for a second).
153 * 228 3/21/98 7:36p Lawrance
154 * Move jump nodes to own lib.
156 * 227 3/19/98 3:37p Adam
157 * Fixed Int3() when you try to right click on a briefing icon.
159 * 226 3/16/98 5:05p Hoffoss
160 * Fixed viewpoint bug.
162 * 225 3/12/98 2:21p Johnson
163 * Fixed some Fred bugs related to jump nodes.
165 * 224 3/10/98 6:11p Hoffoss
166 * Added jump node renaming abilities to Fred.
168 * 223 3/10/98 4:26p Hoffoss
169 * Changed jump node structure to include a name. Position is now taken
170 * from the object (each jump node has an associated object now).
172 * 222 3/09/98 10:03p Hoffoss
173 * Added support for loading/saving jump nodes to mission files.
175 * 221 3/09/98 10:56a Hoffoss
176 * Added jump node objects to Fred.
178 * 220 3/05/98 3:59p Hoffoss
179 * Added a bunch of new command brief stuff, and asteroid initialization
182 * 219 2/26/98 4:59p Allender
183 * groundwork for team vs team briefings. Moved weaponry pool into the
184 * Team_data structure. Added team field into the p_info structure.
185 * Allow for mutliple structures in the briefing code.
187 * 218 2/09/98 9:25p Allender
188 * team v team support. multiple pools and breifings
190 * 217 2/07/98 9:13p Hoffoss
191 * Added some more error checking to global error checker.
193 * 216 2/06/98 4:39p Hoffoss
194 * Added better checking for whether Fred is in the foreground or
197 * 215 2/04/98 4:32p Allender
198 * support for multiple briefings and debriefings. Changes to mission
199 * type (now a bitfield). Bitfield defs for multiplayer modes
201 * 214 2/02/98 4:36p Hoffoss
202 * Made no mission title given flag an error.
204 * 213 1/29/98 5:14p Hoffoss
205 * Added error checking for more than 4 ships in a player starting wing.
207 * 212 1/21/98 5:22p Hoffoss
208 * Added check to global error checker to make sure Alpha wing exists for
209 * multiplayer missions.
211 * 211 1/14/98 8:40p Allender
212 * don't check builtin messages when checking persona stuff
214 * 210 1/07/98 11:24p Allender
215 * add latency of 0 to key_mark function calls
217 * 209 12/31/97 3:56p Hoffoss
218 * Forced alpha wing to always have a true arrival cue.
220 * 208 12/09/97 8:11a Allender
221 * have Fred warn on certain starting wing conditions
223 * 207 11/24/97 10:14p Allender
224 * removed num_ships from use!!!! it was creating problems
226 * 206 11/24/97 11:07a Allender
227 * error checking on wings ignoring player orders
229 * 205 11/17/97 4:57p Allender
230 * added persona support in FreeSpace. A couple of new messages for
231 * message.tbl which Dan didn't have
233 * 204 11/14/97 5:21p Johnson
234 * Added debriefing formulas to error checker.
236 * 203 11/05/97 4:43p Allender
237 * reworked medal/rank system to read all data from tables. Made Fred
238 * read medals.tbl. Changed ai-warp to ai-warp-out which doesn't require
239 * waypoint for activation
241 * 202 10/30/97 3:30p Hoffoss
242 * Made anti-aliased gridlines an option in Fred.
244 * 201 10/28/97 9:54a Jasen
245 * don't check for personas when wing is sending message
247 * 200 10/22/97 3:15p Hoffoss
248 * Fixed ai-stay-still initial order to use waypoints instead of waypoint
251 * 199 10/22/97 1:58p Hoffoss
252 * Added support for AI_GOALS_PLAY_DEAD and changed AI_GOALS_STAY_STILL
255 * 198 10/14/97 10:59a Allender
256 * more persona work. Made global error checker call funciton to assign
259 * 197 10/10/97 5:03p Allender
260 * started work on ai-stay-still
262 * 196 10/01/97 12:37p Hoffoss
263 * Changed Fred (and FreeSpace) to utilize alpha, beta and gamma as player
264 * starting wing names.
266 * 195 9/16/97 9:41p Hoffoss
267 * Changed Fred code around to stop using Parse_player structure for
268 * player information, and use actual ships instead.
270 * 194 9/10/97 3:48p Duncan
271 * Added a case that was never added in the past (probably overlooked).
273 * 193 9/09/97 3:39p Sandeep
274 * warning level 4 bugs
276 * 192 9/09/97 2:12p Hoffoss
277 * Added code to allow briefing editor view to be a 1:1 pixel size fixed
278 * as the FreeSpace view will have.
280 * 191 9/06/97 2:13p Mike
281 * Replace support for TEAM_NEUTRAL
283 * 190 9/03/97 4:32p Hoffoss
284 * Added error number range error checking to Fred, and defaulted numbers
285 * for # of times docked to 1 in sexp trees.
287 * 189 9/02/97 4:32p Hoffoss
288 * Made minimized child windows restore if the window is activated.
290 * 188 9/02/97 1:34p Johnson
291 * Fixed bug I swear wasn't there when I checked this in originally.
294 * 187 9/01/97 6:59p Hoffoss
295 * Added source safe checkin and checkout capabilities to Fred.
297 * 186 8/28/97 8:56a Hoffoss
298 * Added more checking to sexp error checker, fixed some bugs.
300 * 185 8/26/97 4:18p Hoffoss
301 * Added error checking to initial orders dialog when ok is clicked.
303 * 184 8/25/97 5:58p Hoffoss
304 * Created menu items for keypress functions in Fred, and fixed bug this
305 * uncovered with wing_delete function.
307 * 183 8/22/97 4:16p Hoffoss
308 * added support for arrival and departure info in ship editor using
309 * wing's info if editing marked ships in a wing instead of using ship's.
311 * 182 8/18/97 9:31p Hoffoss
312 * Added grid adjustment dialog and shield system editor dialog.
314 * 181 8/17/97 10:22p Hoffoss
315 * Fixed several bugs in Fred with Undo feature. In the process, recoded
316 * a lot of CFile.cpp.
318 * 180 8/16/97 5:23p Hoffoss
319 * Added restrictions for single player mission type to allow only 1
322 * 179 8/16/97 2:02a Hoffoss
323 * Made docked objects move together in Fred.
325 * 178 8/15/97 11:08a Hoffoss
326 * Created a list of order types that can be used for several things, and
327 * yet easily changable. Added order error checking against ship types.
329 * 177 8/15/97 1:07a Hoffoss
330 * Changed code to disallow some ship types from being in a wing, and
331 * disallowing some ship types from being able to have initial orders.
333 * 176 8/14/97 6:37p Hoffoss
334 * Added briefing icon id support to Fred.
336 * 175 8/14/97 2:32p Hoffoss
337 * fixed bug where controlling an object doesn't cause screen updates, and
338 * added a number of cool features to viewpoint/control object code.
340 * 174 8/14/97 9:30a Hoffoss
341 * Added support for new ai goals "stay near ship" and "keep safe
344 * 173 8/13/97 6:23p Hoffoss
345 * Fixed initially docked code in Fred.
347 * 172 8/13/97 5:40p Hoffoss
350 * 171 8/12/97 10:42p Hoffoss
351 * Changed code to campaign editor load an accelerator table when created.
353 * 170 8/12/97 6:32p Hoffoss
354 * Added code to allow hiding of arrival and departure cues in editors.
356 * 169 8/12/97 5:56p Johnson
357 * Fixed bug with global error checker. Initially docked ships flagged as
358 * error when they aren't really.
360 * 168 8/12/97 1:29p Duncan
361 * Fixed bug with ai_undock initial order.
363 * 167 8/11/97 7:11p Hoffoss
364 * Somehow SS didn't merge the files, so I've reconstructed the changes
367 * 166 8/11/97 6:54p Hoffoss
368 * Groups now supported in Fred.
370 * 165 8/11/97 11:51a Allender
371 * added stamp stuff to Fred
373 * 164 8/07/97 6:01p Hoffoss
374 * Added a rotate about selected object button to toolbar and
375 * functionality, as requested by Comet.
377 * 163 8/07/97 2:07p Hoffoss
378 * Added duplicate icon label error checking to global error checker, and
379 * made briefign mode boxmark only icons if at least one icon is in the
382 * 162 8/06/97 10:20a Hoffoss
383 * Changed rotation speeds to be less linear and hopefully more useful.
385 * 161 8/05/97 2:27p Jasen
386 * Fixed bug in global error checker that caused crashes when in briefing
389 * 160 8/05/97 1:31p Hoffoss
390 * Removed excessive source control info from header.
392 * 159 8/01/97 5:52p Hoffoss
393 * Changed initially docked to disallow illegal docking combinations, and
394 * changed error checker to check for this as well.
396 * 158 8/01/97 3:10p Hoffoss
397 * Made Sexp help hidable.
399 * 157 8/01/97 12:52p Hoffoss
400 * Added variable, fixed bug with global error check.
402 * 156 7/31/97 6:41p Hoffoss
403 * Added checks to global error checker.
405 * 155 7/30/97 4:30p Hoffoss
406 * Made Fred sexp error checker more explicit.
408 * 154 7/29/97 5:16p Hoffoss
409 * Fixed bug in ship_query_general_type() and added docking checking to
410 * Fred's error checking.
412 * 153 7/29/97 1:44p Hoffoss
413 * Make player ships exception to ship target within same wing error
423 #include "fredview.h"
424 #include "fredrender.h"
429 #include "management.h"
433 #include "linklist.h"
434 #include "fvi.h" // For find_plane_line_intersection
440 #include "ship.h" // for ship names
441 #include "missiongoalsdlg.h"
443 #include "ship_select.h"
444 #include "playerstarteditor.h"
445 #include "orienteditor.h"
446 #include "eventeditor.h"
447 #include "messageeditordlg.h"
448 #include "starfield.h"
449 #include "starfieldeditor.h"
450 #include "floating.h"
451 #include "reinforcementeditordlg.h"
452 #include "asteroideditordlg.h"
453 #include "campaigntreewnd.h"
454 #include "debriefingeditordlg.h"
455 #include "adjustgriddlg.h"
456 #include "shieldsysdlg.h"
457 #include "cmdbrief.h"
458 #include "jumpnode.h"
459 #include "dumpstats.h"
462 #define new DEBUG_NEW
464 static char THIS_FILE[] = __FILE__;
467 subsys_to_render Render_subsys;
469 // the next variable is used for executable stamping -- please leave it alone!!!
470 #define FRED_EXPIRE_TIME (7 * 1000)
471 char stamp[STAMP_STRING_LENGTH] = { STAMP_STRING };
474 #define EXPIRE_BAD_CHECKSUM 1
475 #define EXPIRE_BAD_TIME 2
477 #define SHIP_TYPES 8000
478 #define REDUCER 100.0f
479 #define DUP_DRAG_OF_WING 2
481 LOCAL int Duped_wing;
483 int Autosave_disabled = 0;
484 int Show_sexp_help = 1;
487 int Show_friendly = 1;
488 int Show_hostile = 1;
489 int Show_neutral = 1;
490 int Show_ship_info = 1;
491 int Show_ship_models = 0;
492 int Show_compass = 1;
493 int Show_dock_points = 0;
494 int Show_paths_fred = 0;
495 int Selection_lock = 0;
499 int Marked = 0, moved = 0;
501 int Cursor_over = -1;
503 int physics_speed = 1;
504 int physics_rot = 20;
506 int last_mouse_x, last_mouse_y, mouse_dx, mouse_dy;
508 int Id_select_type_jump_node;
509 int Id_select_type_start = 0;
510 int Id_select_type_waypoint = 0;
511 int Hide_ship_cues = 0, Hide_wing_cues = 0;
512 vector original_pos, saved_cam_pos;
513 matrix bitmap_matrix_backup, saved_cam_orient = { 0.0f };
514 Marking_box marking_box;
515 object_orient_pos rotation_backup[MAX_OBJECTS];
517 // used by error checker, but needed in more than just one function.
518 char *names[MAX_OBJECTS], flags[MAX_OBJECTS];
522 void view_universe(int just_marked = 0);
523 void select_objects();
524 void drag_rotate_save_backup();
526 /////////////////////////////////////////////////////////////////////////////
529 CFREDView *Fred_view_wnd = NULL;
531 IMPLEMENT_DYNCREATE(CFREDView, CView)
533 BEGIN_MESSAGE_MAP(CFREDView, CView)
534 ON_MESSAGE(WM_GOODBYE, OnGoodbye)
535 ON_MESSAGE(WM_MENU_POPUP_SHIPS, OnMenuPopupShips)
536 ON_MESSAGE(WM_MENU_POPUP_EDIT, OnMenuPopupEdit)
538 //{{AFX_MSG_MAP(CFREDView)
539 ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
540 ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
541 ON_COMMAND(ID_SHOW_WAYPOINTS, OnViewWaypoints)
542 ON_UPDATE_COMMAND_UI(ID_SHOW_WAYPOINTS, OnUpdateViewWaypoints)
544 ON_COMMAND(ID_EDITORS_SHIPS, OnEditorsShips)
552 ON_COMMAND(ID_MISCSTUFF_SHOWSHIPSASICONS, OnMiscstuffShowshipsasicons)
554 ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnEditPopupShowShipIcons)
555 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_ICONS, OnUpdateEditPopupShowShipIcons)
556 ON_COMMAND(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnEditPopupShowShipModels)
557 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_SHIP_MODELS, OnUpdateEditPopupShowShipModels)
559 ON_COMMAND(ID_SHOW_PATHS, OnShowPaths)
560 ON_UPDATE_COMMAND_UI(ID_SHOW_PATHS, OnUpdateShowPaths)
561 ON_COMMAND(ID_SHOW_DOCK_POINTS, OnShowDockPoints)
562 ON_UPDATE_COMMAND_UI(ID_SHOW_DOCK_POINTS, OnUpdateShowDockPoints)
564 ON_COMMAND(ID_MISC_STATISTICS, OnMiscStatistics)
565 ON_COMMAND(ID_EDIT_POPUP_SHOW_COMPASS, OnEditPopupShowCompass)
566 ON_UPDATE_COMMAND_UI(ID_EDIT_POPUP_SHOW_COMPASS, OnUpdateEditPopupShowCompass)
567 ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_EXTERNAL, OnUpdateChangeViewpointExternal)
568 ON_COMMAND(ID_CHANGE_VIEWPOINT_EXTERNAL, OnChangeViewpointExternal)
569 ON_UPDATE_COMMAND_UI(ID_CHANGE_VIEWPOINT_FOLLOW, OnUpdateChangeViewpointFollow)
570 ON_COMMAND(ID_CHANGE_VIEWPOINT_FOLLOW, OnChangeViewpointFollow)
571 ON_COMMAND(ID_EDITORS_GOALS, OnEditorsGoals)
572 ON_COMMAND(ID_SPEED1, OnSpeed1)
573 ON_COMMAND(ID_SPEED2, OnSpeed2)
574 ON_COMMAND(ID_SPEED5, OnSpeed5)
575 ON_COMMAND(ID_SPEED10, OnSpeed10)
576 ON_UPDATE_COMMAND_UI(ID_SPEED1, OnUpdateSpeed1)
577 ON_COMMAND(ID_SPEED3, OnSpeed3)
578 ON_COMMAND(ID_SPEED8, OnSpeed8)
579 ON_COMMAND(ID_ROT1, OnRot1)
580 ON_COMMAND(ID_ROT2, OnRot2)
581 ON_COMMAND(ID_ROT3, OnRot3)
582 ON_COMMAND(ID_ROT4, OnRot4)
583 ON_COMMAND(ID_ROT5, OnRot5)
584 ON_UPDATE_COMMAND_UI(ID_SPEED2, OnUpdateSpeed2)
585 ON_UPDATE_COMMAND_UI(ID_SPEED3, OnUpdateSpeed3)
586 ON_UPDATE_COMMAND_UI(ID_SPEED5, OnUpdateSpeed5)
587 ON_UPDATE_COMMAND_UI(ID_SPEED8, OnUpdateSpeed8)
588 ON_UPDATE_COMMAND_UI(ID_SPEED10, OnUpdateSpeed10)
589 ON_UPDATE_COMMAND_UI(ID_ROT1, OnUpdateRot1)
590 ON_UPDATE_COMMAND_UI(ID_ROT2, OnUpdateRot2)
591 ON_UPDATE_COMMAND_UI(ID_ROT3, OnUpdateRot3)
592 ON_UPDATE_COMMAND_UI(ID_ROT4, OnUpdateRot4)
593 ON_UPDATE_COMMAND_UI(ID_ROT5, OnUpdateRot5)
594 ON_COMMAND(ID_CONTROL_MODE_CAMERA, OnControlModeCamera)
595 ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_CAMERA, OnUpdateControlModeCamera)
596 ON_COMMAND(ID_CONTROL_MODE_SHIP, OnControlModeShip)
597 ON_UPDATE_COMMAND_UI(ID_CONTROL_MODE_SHIP, OnUpdateControlModeShip)
598 ON_COMMAND(ID_SHOW_GRID_POSITIONS, OnShowGridPositions)
599 ON_UPDATE_COMMAND_UI(ID_SHOW_GRID_POSITIONS, OnUpdateShowGridPositions)
600 ON_COMMAND(ID_SHOW_COORDINATES, OnShowCoordinates)
601 ON_UPDATE_COMMAND_UI(ID_SHOW_COORDINATES, OnUpdateShowCoordinates)
602 ON_COMMAND(ID_SPEED50, OnSpeed50)
603 ON_UPDATE_COMMAND_UI(ID_SPEED50, OnUpdateSpeed50)
604 ON_COMMAND(ID_SPEED100, OnSpeed100)
605 ON_UPDATE_COMMAND_UI(ID_SPEED100, OnUpdateSpeed100)
606 ON_COMMAND(ID_SELECT, OnSelect)
607 ON_UPDATE_COMMAND_UI(ID_SELECT, OnUpdateSelect)
608 ON_COMMAND(ID_SELECT_AND_MOVE, OnSelectAndMove)
609 ON_UPDATE_COMMAND_UI(ID_SELECT_AND_MOVE, OnUpdateSelectAndMove)
610 ON_COMMAND(ID_SELECT_AND_ROTATE, OnSelectAndRotate)
611 ON_UPDATE_COMMAND_UI(ID_SELECT_AND_ROTATE, OnUpdateSelectAndRotate)
612 ON_COMMAND(ID_CONSTRAIN_X, OnConstrainX)
613 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_X, OnUpdateConstrainX)
614 ON_COMMAND(ID_CONSTRAIN_Y, OnConstrainY)
615 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Y, OnUpdateConstrainY)
616 ON_COMMAND(ID_CONSTRAIN_Z, OnConstrainZ)
617 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_Z, OnUpdateConstrainZ)
618 ON_COMMAND(ID_CONSTRAIN_XZ, OnConstrainXz)
619 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XZ, OnUpdateConstrainXz)
620 ON_COMMAND(ID_SELECTION_LOCK, OnSelectionLock)
621 ON_UPDATE_COMMAND_UI(ID_SELECTION_LOCK, OnUpdateSelectionLock)
622 ON_WM_LBUTTONDBLCLK()
623 ON_COMMAND(ID_DOUBLE_FINE_GRIDLINES, OnDoubleFineGridlines)
624 ON_UPDATE_COMMAND_UI(ID_DOUBLE_FINE_GRIDLINES, OnUpdateDoubleFineGridlines)
625 ON_COMMAND(ID_SHOW_DISTANCES, OnShowDistances)
626 ON_UPDATE_COMMAND_UI(ID_SHOW_DISTANCES, OnUpdateShowDistances)
627 ON_COMMAND(ID_UNIVERSAL_HEADING, OnUniversalHeading)
628 ON_UPDATE_COMMAND_UI(ID_UNIVERSAL_HEADING, OnUpdateUniversalHeading)
629 ON_COMMAND(ID_FLYING_CONTROLS, OnFlyingControls)
630 ON_UPDATE_COMMAND_UI(ID_FLYING_CONTROLS, OnUpdateFlyingControls)
631 ON_COMMAND(ID_ROTATE_LOCALLY, OnRotateLocally)
632 ON_UPDATE_COMMAND_UI(ID_ROTATE_LOCALLY, OnUpdateRotateLocally)
633 ON_COMMAND(ID_CONSTRAIN_XY, OnConstrainXy)
634 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_XY, OnUpdateConstrainXy)
635 ON_UPDATE_COMMAND_UI(ID_CONSTRAIN_YZ, OnUpdateConstrainYz)
636 ON_COMMAND(ID_CONSTRAIN_YZ, OnConstrainYz)
637 ON_COMMAND(ID_SELECT_LIST, OnSelectList)
638 ON_COMMAND(ID_ZOOM_EXTENTS, OnZoomExtents)
639 ON_COMMAND(ID_ZOOM_SELECTED, OnZoomSelected)
640 ON_UPDATE_COMMAND_UI(ID_ZOOM_SELECTED, OnUpdateZoomSelected)
641 ON_COMMAND(ID_FORM_WING, OnFormWing)
642 ON_UPDATE_COMMAND_UI(ID_FORM_WING, OnUpdateFormWing)
643 ON_COMMAND(ID_DISBAND_WING, OnDisbandWing)
644 ON_UPDATE_COMMAND_UI(ID_DISBAND_WING, OnUpdateDisbandWing)
645 ON_COMMAND(ID_SHOW_HORIZON, OnShowHorizon)
646 ON_UPDATE_COMMAND_UI(ID_SHOW_HORIZON, OnUpdateShowHorizon)
647 ON_COMMAND(ID_EDITORS_WING, OnEditorsWing)
648 ON_COMMAND(ID_EDITORS_PLAYER, OnEditorsPlayer)
649 ON_COMMAND(ID_EDITORS_ORIENT, OnEditorsOrient)
650 ON_COMMAND(ID_EDITORS_EVENTS, OnEditorsEvents)
651 ON_UPDATE_COMMAND_UI(ID_EDITORS_ORIENT, OnUpdateEditorsOrient)
652 ON_COMMAND(ID_EDITORS_MESSAGE, OnEditorsMessage)
653 ON_COMMAND(ID_EDITORS_STARFIELD, OnEditorsStarfield)
654 ON_COMMAND(ID_EDITORS_BG_BITMAPS, OnEditorsBgBitmaps)
655 ON_COMMAND(ID_EDITORS_REINFORCEMENT, OnEditorsReinforcement)
656 ON_COMMAND(ID_ERROR_CHECKER, OnErrorChecker)
657 ON_COMMAND(ID_EDITORS_WAYPOINT, OnEditorsWaypoint)
658 ON_COMMAND(ID_VIEW_OUTLINES, OnViewOutlines)
659 ON_UPDATE_COMMAND_UI(ID_VIEW_OUTLINES, OnUpdateViewOutlines)
660 ON_UPDATE_COMMAND_UI(ID_NEW_SHIP_TYPE, OnUpdateNewShipType)
661 ON_COMMAND(ID_SHOW_STARFIELD, OnShowStarfield)
662 ON_UPDATE_COMMAND_UI(ID_SHOW_STARFIELD, OnUpdateShowStarfield)
663 ON_COMMAND(ID_ASTEROID_EDITOR, OnAsteroidEditor)
664 ON_COMMAND(ID_RUN_FREESPACE, OnRunFreespace)
665 ON_COMMAND(ID_EDITOR_CAMPAIGN, OnEditorCampaign)
666 ON_COMMAND(ID_SHOW_SHIPS, OnShowShips)
667 ON_UPDATE_COMMAND_UI(ID_SHOW_SHIPS, OnUpdateShowShips)
668 ON_COMMAND(ID_SHOW_STARTS, OnShowStarts)
669 ON_UPDATE_COMMAND_UI(ID_SHOW_STARTS, OnUpdateShowStarts)
670 ON_COMMAND(ID_SHOW_FRIENDLY, OnShowFriendly)
671 ON_UPDATE_COMMAND_UI(ID_SHOW_FRIENDLY, OnUpdateShowFriendly)
672 ON_COMMAND(ID_SHOW_HOSTILE, OnShowHostile)
673 ON_UPDATE_COMMAND_UI(ID_SHOW_HOSTILE, OnUpdateShowHostile)
674 ON_COMMAND(ID_TOGGLE_VIEWPOINT, OnToggleViewpoint)
675 ON_COMMAND(ID_REVERT, OnRevert)
676 ON_UPDATE_COMMAND_UI(ID_REVERT, OnUpdateRevert)
678 ON_COMMAND(ID_HIDE_OBJECTS, OnHideObjects)
679 ON_COMMAND(ID_SHOW_HIDDEN_OBJECTS, OnShowHiddenObjects)
680 ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
681 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
682 ON_COMMAND(ID_EDITORS_BRIEFING, OnEditorsBriefing)
683 ON_COMMAND(ID_EDITORS_DEBRIEFING, OnEditorsDebriefing)
684 ON_COMMAND(ID_SAVE_CAMERA, OnSaveCamera)
685 ON_COMMAND(ID_RESTORE_CAMERA, OnRestoreCamera)
686 ON_UPDATE_COMMAND_UI(ID_RESTORE_CAMERA, OnUpdateRestoreCamera)
687 ON_COMMAND(ID_SHOW_SEXP_HELP, OnShowSexpHelp)
688 ON_UPDATE_COMMAND_UI(ID_SHOW_SEXP_HELP, OnUpdateShowSexpHelp)
689 ON_COMMAND(ID_LOOKAT_OBJ, OnLookatObj)
690 ON_UPDATE_COMMAND_UI(ID_LOOKAT_OBJ, OnUpdateLookatObj)
691 ON_COMMAND(ID_EDITORS_ADJUST_GRID, OnEditorsAdjustGrid)
692 ON_COMMAND(ID_EDITORS_SHIELD_SYS, OnEditorsShieldSys)
693 ON_COMMAND(ID_LEVEL_OBJ, OnLevelObj)
694 ON_COMMAND(ID_ALIGN_OBJ, OnAlignObj)
695 ON_COMMAND(ID_CONTROL_OBJ, OnControlObj)
696 ON_COMMAND(ID_NEXT_OBJ, OnNextObj)
697 ON_COMMAND(ID_PREV_OBJ, OnPrevObj)
698 ON_COMMAND(ID_EDIT_DELETE_WING, OnEditDeleteWing)
699 ON_COMMAND(ID_MARK_WING, OnMarkWing)
700 ON_UPDATE_COMMAND_UI(ID_CONTROL_OBJ, OnUpdateControlObj)
701 ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
702 ON_COMMAND(ID_AA_GRIDLINES, OnAaGridlines)
703 ON_UPDATE_COMMAND_UI(ID_AA_GRIDLINES, OnUpdateAaGridlines)
704 ON_COMMAND(ID_CMD_BRIEF, OnCmdBrief)
705 ON_COMMAND(ID_DISABLE_UNDO, OnDisableUndo)
706 ON_UPDATE_COMMAND_UI(ID_DISABLE_UNDO, OnUpdateDisableUndo)
707 ON_UPDATE_COMMAND_UI(ID_CMD_BRIEF, OnUpdateCmdBrief)
708 ON_COMMAND(ID_NEXT_SUBSYS, OnNextSubsys)
709 ON_COMMAND(ID_PREV_SUBSYS, OnPrevSubsys)
710 ON_COMMAND(ID_CANCEL_SUBSYS, OnCancelSubsys)
711 ON_COMMAND(ID_DUMP_STATS, OnDumpStats)
713 ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
714 ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
715 ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
716 ON_COMMAND_RANGE(ID_GROUP1, ID_GROUP9, OnGroup)
717 ON_COMMAND_RANGE(ID_SET_GROUP1, ID_SET_GROUP9, OnSetGroup)
720 /////////////////////////////////////////////////////////////////////////////
721 // CFREDView construction/destruction
723 CFREDView::CFREDView()
725 //m_ConfirmDeleting = TRUE;
726 //m_ShowCapitalShips = TRUE;
727 //m_ShowElevations = TRUE;
728 //m_ShowFighters = TRUE;
730 //m_ShowMiscObjects = TRUE;
731 //m_ShowPlanets = TRUE;
732 //m_ShowWaypoints = TRUE;
734 m_pGDlg = new CGrid(this);
738 //if (!(int errno = gr_init(640, 480, 32)))
739 // Error(LOCATION, "Hey, gr_init failed! Error code = %i", errno);
740 Fred_view_wnd = this;
743 CFREDView::~CFREDView()
750 void CALLBACK expire_game_proc( HWND wnd, UINT uMsg, UINT idEvent, DWORD dwTime)
753 if ( expire_game == EXPIRE_BAD_CHECKSUM )
754 MessageBox (wnd, "Fred can no longer run due to internal overlay error", NULL, MB_OK | MB_ICONERROR |MB_TASKMODAL|MB_SETFOREGROUND);
756 MessageBox (wnd, "Error: cannot enter DOS mode for 80x40 color text mode display.", NULL, MB_OK | MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND);
760 BOOL CFREDView::PreCreateWindow(CREATESTRUCT& cs)
764 casperl = CView::PreCreateWindow(cs);
765 cs.y = 0; // doesn't seem to do anything. :(
767 // other miscellaneous initializations
768 cfile_chdir("data\\missions");
769 set_physics_controls();
773 /////////////////////////////////////////////////////////////////////////////
776 void CFREDView::OnDraw(CDC* pDC)
780 CFREDDoc* pDoc = GetDocument();
787 pDC->GetClipBox(&clip);
788 gr_set_clip(clip.left, clip.top, clip.right - clip.left + 1, clip.bottom - clip.top + 1);
789 Assert(clip.left <= clip.right);
790 Assert(clip.top <= clip.bottom);
791 gr_flip_window((uint) pDC->m_hDC, clip.left, clip.top,
792 clip.right - clip.left + 1, clip.bottom - clip.top + 1);
795 /////////////////////////////////////////////////////////////////////////////
796 // CFREDView printing
798 BOOL CFREDView::OnPreparePrinting(CPrintInfo* pInfo)
800 // default preparation
801 return DoPreparePrinting(pInfo);
804 void CFREDView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
806 // TODO: add extra initialization before printing
809 void CFREDView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
811 // TODO: add cleanup after printing
814 /////////////////////////////////////////////////////////////////////////////
815 // CFREDView diagnostics
818 void CFREDView::AssertValid() const
820 CView::AssertValid();
823 void CFREDView::Dump(CDumpContext& dc) const
828 CFREDDoc* CFREDView::GetDocument() // non-debug version is inline
830 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFREDDoc)));
831 return (CFREDDoc*)m_pDocument;
835 /////////////////////////////////////////////////////////////////////////////
836 // CFREDView message handlers
838 void CFREDView::OnViewGrid()
840 Show_grid = !Show_grid;
844 void CFREDView::OnUpdateViewGrid(CCmdUI* pCmdUI)
846 pCmdUI->SetCheck(Show_grid);
849 void CFREDView::OnViewWaypoints()
851 Show_waypoints = !Show_waypoints;
855 void CFREDView::OnUpdateViewWaypoints(CCmdUI* pCmdUI)
857 pCmdUI->SetCheck(Show_waypoints);
860 #define MAX_MOVE_DISTANCE 25.0f
862 // If cur_object_index references a valid object, drag it from its current
863 // location to the new cursor location specified by "point".
864 // It is dragged relative to the main grid. It's y coordinate is not changed.
865 // Return value: 0/1 = didn't/did move object all the way to goal.
868 int z, cobj, flag, rval = 1;
870 float distance_moved = 0.0f;
871 vector cursor_dir, int_pnt;
872 vector movement_vector;
876 // starfield_bitmaps *bmp;
879 if (Bg_bitmap_dialog) {
883 bmp = &Starfield_bitmaps[Cur_bitmap];
884 if (Single_axis_constraint && Constraint.z) {
885 bmp->dist *= 1.0f + mouse_dx / -800.0f;
886 calculate_bitmap_points(bmp, 0.0f);
889 g3_point_to_vec_delayed(&bmp->m.fvec, marking_box.x2, marking_box.y2);
890 vm_orthogonalize_matrix(&bmp->m);
891 calculate_bitmap_points(bmp, 0.0f);
897 if (!query_valid_object())
900 if ((Dup_drag == 1) && (Briefing_dialog))
904 dup_object(NULL); // reset waypoint list
905 cobj = Duped_wing = -1;
907 objp = GET_FIRST(&obj_used_list);
908 while (objp != END_OF_LIST(&obj_used_list)) {
909 Assert(objp->type != OBJ_NONE);
910 if (objp->flags & OF_MARKED) {
911 if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) {
912 z = Ships[objp->instance].wingnum;
915 else if (Duped_wing != z)
922 z = dup_object(objp);
928 if (cur_object_index == OBJ_INDEX(objp) )
932 objp = GET_NEXT(objp);
935 obj_merge_created_list();
937 objp = GET_FIRST(&obj_used_list);
938 while (objp != END_OF_LIST(&obj_used_list)) {
939 ptr = GET_NEXT(objp);
940 if (objp->flags & OF_TEMP_MARKED)
952 objp = GET_FIRST(&obj_used_list);
953 while (objp != END_OF_LIST(&obj_used_list)) {
954 if (objp->flags & OF_TEMP_MARKED) {
955 objp->flags &= ~OF_TEMP_MARKED;
956 mark_object(OBJ_INDEX(objp));
959 objp = GET_NEXT(objp);
962 set_cur_object_index(cobj);
963 if (Duped_wing != -1)
964 Dup_drag = DUP_DRAG_OF_WING; // indication for later that we duped objects in a wing
968 drag_rotate_save_backup();
973 objp = &Objects[cur_object_index];
974 Assert(objp->type != OBJ_NONE);
975 obj = int_pnt = objp->pos;
977 // Get 3d vector specified by mouse cursor location.
978 g3_point_to_vec_delayed(&cursor_dir, marking_box.x2, marking_box.y2);
979 if (Single_axis_constraint) {
980 // if (fvi_ray_plane(&int_pnt, &obj, &view_orient.fvec, &view_pos, &cursor_dir, 0.0f) >= 0.0f ) {
981 // vm_vec_add(&p1, &obj, &Constraint);
982 // find_nearest_point_on_line(&nearest_point, &obj, &p1, &int_pnt);
983 // int_pnt = nearest_point;
984 // distance_moved = vm_vec_dist(&obj, &int_pnt);
987 vector tmpAnticonstraint = Anticonstraint;
988 vector tmpObject = obj;
990 tmpAnticonstraint.x = 0.0f;
991 r = fvi_ray_plane(&int_pnt, &tmpObject, &tmpAnticonstraint, &view_pos, &cursor_dir, 0.0f);
993 // If intersected behind viewer, don't move. Too confusing, not what user wants.
994 vm_vec_sub(&vec1, &int_pnt, &view_pos);
995 vm_vec_sub(&vec2, &obj, &view_pos);
996 if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f)) {
998 vm_vec_sub( &tmp1, &int_pnt, &obj );
999 tmp1.x *= Constraint.x;
1000 tmp1.y *= Constraint.y;
1001 tmp1.z *= Constraint.z;
1002 vm_vec_add( &int_pnt, &obj, &tmp1 );
1004 distance_moved = vm_vec_dist(&obj, &int_pnt);
1008 } else { // Move in x-z plane, defined by grid. Preserve height.
1009 r = fvi_ray_plane(&int_pnt, &obj, &Anticonstraint, &view_pos, &cursor_dir, 0.0f);
1011 // If intersected behind viewer, don't move. Too confusing, not what user wants.
1012 vm_vec_sub(&vec1, &int_pnt, &view_pos);
1013 vm_vec_sub(&vec2, &obj, &view_pos);
1014 if ((r>=0.0f) && (vm_vec_dot(&vec1, &vec2) >= 0.0f))
1015 distance_moved = vm_vec_dist(&obj, &int_pnt);
1018 // If moved too far, then move max distance along vector.
1019 vm_vec_sub(&movement_vector, &int_pnt, &obj);
1020 /* if (distance_moved > MAX_MOVE_DISTANCE) {
1021 vm_vec_normalize(&movement_vector);
1022 vm_vec_scale(&movement_vector, MAX_MOVE_DISTANCE);
1025 if (distance_moved) {
1026 objp = GET_FIRST(&obj_used_list);
1027 while (objp != END_OF_LIST(&obj_used_list)) {
1028 Assert(objp->type != OBJ_NONE);
1029 if (objp->flags & OF_MARKED) {
1030 vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
1031 if (objp->type == OBJ_WAYPOINT) {
1032 Waypoint_lists[objp->instance / 65536].waypoints[objp->instance & 0xffff] =
1037 objp = GET_NEXT(objp);
1040 objp = GET_FIRST(&obj_used_list);
1041 while (objp != END_OF_LIST(&obj_used_list)) {
1042 if (objp->flags & OF_MARKED)
1045 objp = GET_NEXT(objp);
1049 if (Briefing_dialog)
1050 Briefing_dialog->update_positions();
1056 void drag_rotate_save_backup()
1061 if (Cur_bitmap != -1)
1062 bitmap_matrix_backup = Starfield_bitmaps[Cur_bitmap].m;
1065 objp = GET_FIRST(&obj_used_list);
1066 while (objp != END_OF_LIST(&obj_used_list)) {
1067 Assert(objp->type != OBJ_NONE);
1068 if (objp->flags & OF_MARKED) {
1069 rotation_backup[OBJ_INDEX(objp)].pos = objp->pos;
1070 rotation_backup[OBJ_INDEX(objp)].orient = objp->orient;
1073 objp = GET_NEXT(objp);
1077 int drag_rotate_objects()
1080 vector int_pnt, obj;
1082 matrix leader_orient, leader_transpose, tmp, newmat, rotmat;
1083 object *leader, *objp;
1084 // starfield_bitmaps *bmp;
1088 if (Bg_bitmap_dialog) {
1092 bmp = &Starfield_bitmaps[Cur_bitmap];
1093 calculate_bitmap_points(bmp, mouse_dx / -300.0f);
1098 if (!query_valid_object()){
1102 objp = &Objects[cur_object_index];
1103 Assert(objp->type != OBJ_NONE);
1104 obj = int_pnt = objp->pos;
1106 memset(&a, 0, sizeof(angles));
1107 if (Single_axis_constraint) {
1109 a.p = mouse_dy / REDUCER;
1110 else if (Constraint.y)
1111 a.h = mouse_dx / REDUCER;
1112 else if (Constraint.z)
1113 a.b = -mouse_dx / REDUCER;
1116 if (!Constraint.x) { // yz
1117 a.b = -mouse_dx / REDUCER;
1118 a.h = mouse_dy / REDUCER;
1119 } else if (!Constraint.y) { // xz
1120 a.p = mouse_dy / REDUCER;
1121 a.b = -mouse_dx / REDUCER;
1122 } else if (!Constraint.z) { // xy
1123 a.p = mouse_dy / REDUCER;
1124 a.h = mouse_dx / REDUCER;
1128 leader = &Objects[cur_object_index];
1129 leader_orient = leader->orient; // save original orientation
1130 vm_copy_transpose_matrix(&leader_transpose, &leader_orient);
1132 vm_angles_2_matrix(&rotmat, &a);
1133 vm_matrix_x_matrix(&newmat, &leader->orient, &rotmat);
1134 leader->orient = newmat;
1136 objp = GET_FIRST(&obj_used_list);
1137 while (objp != END_OF_LIST(&obj_used_list)) {
1138 Assert(objp->type != OBJ_NONE);
1139 if ((objp->flags & OF_MARKED) && (cur_object_index != OBJ_INDEX(objp) )) {
1142 vector tmpv1, tmpv2;
1144 // change rotation matrix to rotate in opposite direction. This rotation
1145 // matrix is what the leader ship has rotated by.
1146 vm_copy_transpose_matrix(&rot_trans, &rotmat);
1148 // get point relative to our point of rotation (make POR the origin).
1149 vm_vec_sub(&tmpv1, &objp->pos, &leader->pos);
1151 // convert point from real-world coordinates to leader's relative coordinate
1152 // system (z=forward vec, y=up vec, x=right vec
1153 vm_vec_rotate(&tmpv2, &tmpv1, &leader_orient);
1155 // now rotate the point by the transpose from above.
1156 vm_vec_rotate(&tmpv1, &tmpv2, &rot_trans);
1158 // convert point back into real-world coordinates
1159 vm_vec_rotate(&tmpv2, &tmpv1, &leader_transpose);
1161 // and move origin back to real-world origin. Object is now at it's correct
1163 vm_vec_add(&objp->pos, &leader->pos, &tmpv2);
1165 // Now fix the object's orientation to what it should be.
1166 vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
1167 vm_orthogonalize_matrix(&tmp); // safety check
1171 vm_matrix_x_matrix(&tmp, &objp->orient, &rotmat);
1176 objp = GET_NEXT(objp);
1179 objp = GET_FIRST(&obj_used_list);
1180 while (objp != END_OF_LIST(&obj_used_list)) {
1181 if (objp->flags & OF_MARKED)
1184 objp = GET_NEXT(objp);
1196 if (Bg_bitmap_dialog) {
1197 Assert(!vm_check_matrix_for_zeros(&bitmap_matrix_backup));
1198 Starfield_bitmaps[Cur_bitmap].m = bitmap_matrix_backup;
1199 calculate_bitmap_points(&Starfield_bitmaps[Cur_bitmap], 0.0f);
1200 button_down = box_marking = 0;
1207 if (Editing_mode == 1) {
1208 vector movement_vector;
1211 if (query_valid_object()) {
1212 objp = &Objects[cur_object_index];
1213 Assert(objp->type != OBJ_NONE);
1214 vm_vec_sub(&movement_vector, &original_pos, &objp->pos);
1216 objp = GET_FIRST(&obj_used_list);
1217 while (objp != END_OF_LIST(&obj_used_list)) {
1218 Assert(objp->type != OBJ_NONE);
1219 if (objp->flags & OF_MARKED)
1220 vm_vec_add(&objp->pos, &objp->pos, &movement_vector);
1222 objp = GET_NEXT(objp);
1226 } else if (Editing_mode == 2) {
1229 objp = GET_FIRST(&obj_used_list);
1230 while (objp != END_OF_LIST(&obj_used_list)) {
1231 Assert(objp->type != OBJ_NONE);
1232 if (objp->flags & OF_MARKED) {
1233 int obj_index = OBJ_INDEX(objp);
1235 if(!IS_VEC_NULL(&rotation_backup[obj_index].orient.rvec) &&
1236 !IS_VEC_NULL(&rotation_backup[obj_index].orient.uvec) &&
1237 !IS_VEC_NULL(&rotation_backup[obj_index].orient.fvec)){
1239 objp->pos = rotation_backup[obj_index].pos;
1240 objp->orient = rotation_backup[obj_index].orient;
1244 objp = GET_NEXT(objp);
1249 button_down = box_marking = 0;
1250 if (Briefing_dialog)
1251 Briefing_dialog->update_positions();
1254 void CFREDView::OnLButtonDown(UINT nFlags, CPoint point)
1259 CView::OnLButtonDown(nFlags, point);
1263 if (cur_waypoint != -1)
1264 list = cur_waypoint_list * 65536 + cur_waypoint;
1266 marking_box.x1 = point.x;
1267 marking_box.y1 = point.y;
1270 on_object = select_object(point.x, point.y);
1273 drag_rotate_save_backup();
1275 if (nFlags & MK_CONTROL) { // add a new object
1276 if (!Bg_bitmap_dialog) {
1277 if (on_object == -1) {
1278 Selection_lock = 0; // force off selection lock
1279 on_object = create_object_on_grid(list);
1286 Selection_lock = 0; // force off selection lock
1287 on_object = Cur_bitmap = create_bg_bitmap();
1288 Bg_bitmap_dialog->update_data();
1290 if (Cur_bitmap == -1)
1291 MessageBox("Background bitmap limit reached.\nCan't add more.");
1295 } else if (!Selection_lock) {
1296 if (Bg_bitmap_dialog) {
1297 Cur_bitmap = on_object;
1298 Bg_bitmap_dialog -> update_data();
1300 } else if ((nFlags & MK_SHIFT) || (on_object == -1) || !(Objects[on_object].flags & OF_MARKED)) {
1301 if (!(nFlags & MK_SHIFT))
1304 if (on_object != -1) {
1305 if (Objects[on_object].flags & OF_MARKED)
1306 unmark_object(on_object);
1308 mark_object(on_object);
1313 if (query_valid_object())
1314 original_pos = Objects[cur_object_index].pos;
1317 if (Selection_lock) {
1318 if (Editing_mode == 1)
1320 else if (Editing_mode == 2)
1321 drag_rotate_objects();
1326 if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
1327 Assert(Briefing_dialog);
1328 Briefing_dialog->icon_select(Objects[cur_object_index].instance);
1331 if (Briefing_dialog)
1332 Briefing_dialog->icon_select(-1);
1335 CView::OnLButtonDown(nFlags, point);
1338 void CFREDView::OnMouseMove(UINT nFlags, CPoint point)
1340 mouse_dx = point.x - last_mouse_x;
1341 mouse_dy = point.y - last_mouse_y;
1342 last_mouse_x = marking_box.x2 = point.x;
1343 last_mouse_y = marking_box.y2 = point.y;
1344 Cursor_over = select_object(point.x, point.y);
1346 if (!(nFlags & MK_LBUTTON))
1349 // The following will cancel a drag operation if another program running in memory
1350 // happens to jump in and take over (such as new email has arrived popup boxes).
1351 if (button_down && GetCapture() != this)
1354 if (!button_down && GetCapture() == this)
1358 if (abs(marking_box.x1 - marking_box.x2) > 1 || abs(marking_box.y1 - marking_box.y2) > 1)
1362 if (on_object != -1 || Selection_lock) {
1363 if (Editing_mode == 1)
1365 else if (Editing_mode == 2)
1366 drag_rotate_objects();
1368 } else if (!Bg_bitmap_dialog)
1371 if (mouse_dx || mouse_dy)
1376 CView::OnMouseMove(nFlags, point);
1379 void CFREDView::OnLButtonUp(UINT nFlags, CPoint point)
1381 marking_box.x2 = point.x;
1382 marking_box.y2 = point.y;
1384 if (button_down && GetCapture() != this)
1387 if (GetCapture() == this)
1391 if ((abs(marking_box.x1 - marking_box.x2) > 1) || (abs(marking_box.y1 - marking_box.y2) > 1))
1395 if ((on_object != -1) || Selection_lock) {
1396 if (Editing_mode == 1)
1398 else if ((Editing_mode == 2) || (Editing_mode == 3))
1399 drag_rotate_objects();
1402 FREDDoc_ptr->autosave("object move");
1408 if (Bg_bitmap_dialog) {
1416 } else if ((!moved && on_object != -1) && !Selection_lock && !(nFlags & MK_SHIFT)) {
1418 mark_object(on_object);
1424 if (Dup_drag == DUP_DRAG_OF_WING) {
1429 sprintf(msg, "Add cloned ships to wing %s?", Wings[Duped_wing].name);
1430 if (MessageBox(msg, "Query", MB_YESNO) == IDYES) {
1431 objp = GET_FIRST(&obj_used_list);
1432 while (objp != END_OF_LIST(&obj_used_list)) {
1433 if (objp->flags & OF_MARKED) {
1434 if (Wings[Duped_wing].wave_count >= MAX_SHIPS_PER_WING) {
1435 MessageBox("Max ships per wing limit reached");
1439 // Can't do player starts, since only player 1 is currently allowed to be in a wing
1441 Assert(objp->type == OBJ_SHIP);
1442 ship = objp->instance;
1443 Assert(Ships[ship].wingnum == -1);
1444 sprintf(Ships[ship].ship_name, "%s %d", Wings[Duped_wing].name,
1445 Wings[Duped_wing].wave_count + 1);
1447 Wings[Duped_wing].ship_index[Wings[Duped_wing].wave_count] = ship;
1448 Ships[ship].wingnum = Duped_wing;
1450 wing_objects[Duped_wing][Wings[Duped_wing].wave_count] = OBJ_INDEX(objp);
1451 Wings[Duped_wing].wave_count++;
1454 objp = GET_NEXT(objp);
1460 if (query_valid_object() && (Marked == 1) && (Objects[cur_object_index].type == OBJ_POINT)) {
1461 Assert(Briefing_dialog);
1462 Briefing_dialog->icon_select(Objects[cur_object_index].instance);
1465 if (Briefing_dialog)
1466 Briefing_dialog->icon_select(-1);
1469 CView::OnLButtonUp(nFlags, point);
1472 // This function never gets called because nothing causes
1473 // the WM_GOODBYE event to occur.
1474 // False! When you close the Ship Dialog, this function is called! --MK, 8/30/96
1475 LONG CFREDView::OnGoodbye(UINT wParam, LONG lParam)
1477 Ship_editor_dialog.DestroyWindow();
1478 Wing_editor_dialog.DestroyWindow();
1483 void CFREDView::OnEditorsShips()
1487 Assert(Ship_editor_dialog.GetSafeHwnd());
1488 if (!Show_sexp_help)
1489 adjust = -SEXP_HELP_BOX_SIZE;
1491 if (!theApp.init_window(&Ship_wnd_data, &Ship_editor_dialog, adjust))
1494 Ship_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
1495 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
1496 Ship_editor_dialog.ShowWindow(SW_RESTORE);
1499 void CFREDView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT lParam)
1503 lKeyData = lParam & 255; // key data
1504 if (lParam & 256) lKeyData += 0x80;
1505 key_mark(lKeyData, 1, 0);
1507 CView::OnKeyDown(nChar, nRepCnt, lParam);
1510 void CFREDView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT lParam)
1514 lKeyData = lParam & 255; // key data
1515 if (lParam & 256) lKeyData += 0x80;
1516 key_mark(lKeyData, 0, 0);
1518 CView::OnKeyUp(nChar, nRepCnt, lParam);
1521 void CFREDView::OnSetFocus(CWnd* pOldWnd)
1523 static int flag = 0;
1529 nprintf(("Fred routing", "OnSetFocus() called\n"));
1531 Ship_editor_dialog.initialize_data(1);
1536 Wing_editor_dialog.initialize_data(1);
1540 /* if (Wing_editor_dialog.verify() == -1)
1543 if (Ship_editor_dialog.verify() == -1)
1546 if (update_dialog_boxes()) {
1547 nprintf(("Fred routing", "OnSetFocus() returned (error occured)\n"));
1549 Ship_editor_dialog.bypass_errors = 0;
1550 Wing_editor_dialog.bypass_errors = 0;
1554 if (Local_modified) {
1555 FREDDoc_ptr->autosave("Editing");
1560 CView::OnSetFocus(pOldWnd);
1561 nprintf(("Fred routing", "Main window focus accepted\n"));
1565 if (GetActiveWindow() != Fred_main_wnd) {
1566 Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1567 nprintf(("Fred routing", "OnSetFocus() had to put main window back on top\n"));
1573 void CFREDView::OnKillFocus(CWnd* pNewWnd)
1575 nprintf(("Fred routing", "OnKillFocus() called\n"));
1578 CView::OnKillFocus(pNewWnd);
1583 void CFREDView::OnSize(UINT nType, int cx, int cy)
1585 CView::OnSize(nType, cx, cy);
1587 if ((cx > 0) && (cy > 0)) {
1588 gr_init(GR_640, GR_SOFTWARE, 8, cx, cy);
1592 void do_trackball_stuff(int nFlags, CPoint point)
1596 if (nFlags & MK_LBUTTON){
1599 if (nFlags & MK_RBUTTON){
1603 move_mouse(btn, point.x, point.y);
1606 // If add_flag != 0, then add found objects to current wing, else create new wing.
1607 void select_objects()
1609 int x, y, valid, icon_mode = 0;
1613 if (marking_box.x1 > marking_box.x2) {
1615 marking_box.x1 = marking_box.x2;
1619 if (marking_box.y1 > marking_box.y2) {
1621 marking_box.y1 = marking_box.y2;
1625 ptr = GET_FIRST(&obj_used_list);
1626 while (ptr != END_OF_LIST(&obj_used_list)) {
1628 if (ptr->flags & OF_HIDDEN)
1631 Assert(ptr->type != OBJ_NONE);
1632 switch (ptr->type) {
1634 if (!Show_waypoints)
1646 switch (Ships[ptr->instance].team) {
1666 g3_rotate_vertex(&v, &ptr->pos);
1667 if (!(v.codes & CC_BEHIND) && valid)
1668 if (!(g3_project_vertex(&v) & PF_OVERFLOW)) {
1672 if (x >= marking_box.x1 && x <= marking_box.x2 && y >= marking_box.y1 && y <= marking_box.y2) {
1673 if (ptr->flags & OF_MARKED)
1674 unmark_object(OBJ_INDEX(ptr));
1676 mark_object(OBJ_INDEX(ptr));
1678 if (ptr->type == OBJ_POINT)
1683 ptr = GET_NEXT(ptr);
1687 ptr = GET_FIRST(&obj_used_list);
1688 while (ptr != END_OF_LIST(&obj_used_list)) {
1689 if ((ptr->flags & OF_MARKED) && (ptr->type != OBJ_POINT))
1690 unmark_object(OBJ_INDEX(ptr));
1692 ptr = GET_NEXT(ptr);
1696 Update_ship = Update_wing = 1;
1699 LONG CFREDView::OnMenuPopupShips(UINT wParam, LONG lParam)
1704 point = * ((CPoint*) lParam);
1706 ClientToScreen(&point);
1708 menu.LoadMenu(IDR_MENU_SHIP_POPUP);
1709 menu.GetSubMenu(0)->TrackPopupMenu(
1710 TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1715 LONG CFREDView::OnMenuPopupEdit(UINT wParam, LONG lParam)
1720 point = * ((CPoint*) lParam);
1722 ClientToScreen(&point);
1724 menu.LoadMenu(IDR_MENU_EDIT_POPUP);
1725 menu.GetSubMenu(0)->TrackPopupMenu(
1726 TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
1731 int g_Ships_as_icons = 0;
1733 void CFREDView::OnMiscstuffShowshipsasicons()
1736 if (g_Ships_as_icons == 0)
1737 g_Ships_as_icons = 1;
1739 g_Ships_as_icons = 0;
1742 // right mouse button popup menu stuff
1743 void CFREDView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
1745 // make sure window is active
1746 // GetParentFrame()->ActivateFrame();
1750 CPoint local = point;
1757 ScreenToClient(&local);
1758 objnum = select_object(local.x, local.y);
1761 set_cur_object_index(objnum);
1762 if (menu.LoadMenu(IDR_MENU_SHIP_POPUP)) {
1763 int id = ID_EDITORS_SHIPS;
1764 CMenu* pPopup = menu.GetSubMenu(0);
1766 ASSERT(pPopup != NULL);
1768 pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, ID_EDITORS_SHIPS, "Edit Marked Ships");
1772 if ((Objects[objnum].type == OBJ_START) || (Objects[objnum].type == OBJ_SHIP))
1773 str.Format("Edit %s", Ships[Objects[objnum].instance].ship_name);
1775 else if (Objects[objnum].type == OBJ_JUMP_NODE) {
1776 id = ID_EDITORS_WAYPOINT;
1777 str.Format("Edit %s", Jump_nodes[Objects[objnum].instance].name);
1779 } else if (Objects[objnum].type == OBJ_WAYPOINT) {
1780 id = ID_EDITORS_WAYPOINT;
1781 str.Format("Edit %s:%d", Waypoint_lists[Objects[objnum].instance / 65536].name,
1782 (Objects[objnum].instance & 0xffff) + 1);
1784 } else if (Objects[objnum].type == OBJ_POINT) {
1789 str = _T("Unknown");
1792 pPopup->ModifyMenu(ID_EDITORS_SHIPS, MF_BYCOMMAND | MF_STRING, id, str);
1795 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()); // use main window for cmds
1799 if (menu.LoadMenu(IDR_MENU_EDIT_POPUP)) {
1801 CMenu* pPopup = menu.GetSubMenu(0);
1802 CMenu shipPopup, player_submenu, species_submenu[MAX_SPECIES_NAMES];
1803 ASSERT(pPopup != NULL);
1805 // create a popup menu based on the ship models read in ship.cpp.
1806 shipPopup.CreatePopupMenu();
1807 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_waypoint, "Waypoint");
1808 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_start, "Player Start");
1809 shipPopup.AppendMenu(MF_STRING | MF_ENABLED, SHIP_TYPES + Id_select_type_jump_node, "Jump Node");
1810 for (i=0; i<MAX_SPECIES_NAMES; i++) {
1811 species_submenu[i].CreatePopupMenu();
1812 shipPopup.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1813 (UINT) species_submenu[i].m_hMenu, Species_names[i]);
1816 for (i=0; i<Num_ship_types; i++)
1817 species_submenu[Ship_info[i].species].AppendMenu(MF_STRING |
1818 MF_ENABLED, SHIP_TYPES + i, Ship_info[i].name);
1820 pPopup->AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
1821 (UINT) shipPopup.m_hMenu, "New Object Type");
1823 CWnd::DrawMenuBar(); // AppendMenu documentation says to do this.
1824 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
1829 void CFREDView::OnEditPopupShowShipIcons()
1831 Show_ship_info = !Show_ship_info;
1832 theApp.write_ini_file();
1836 void CFREDView::OnUpdateEditPopupShowShipIcons(CCmdUI* pCmdUI)
1838 pCmdUI->SetCheck(Show_ship_info);
1841 void CFREDView::OnEditPopupShowShipModels()
1843 Show_ship_models = !Show_ship_models;
1844 theApp.write_ini_file();
1848 void CFREDView::OnUpdateEditPopupShowShipModels(CCmdUI* pCmdUI)
1850 pCmdUI->SetCheck(Show_ship_models);
1853 void CFREDView::OnEditPopupShowCompass()
1855 Show_compass = !Show_compass;
1856 theApp.write_ini_file();
1860 void CFREDView::OnUpdateEditPopupShowCompass(CCmdUI* pCmdUI)
1862 pCmdUI->SetCheck(Show_compass);
1865 // View implementation file
1866 CFREDView *CFREDView::GetView()
1868 CFrameWnd *pFrame = (CFrameWnd *) (AfxGetApp()->m_pMainWnd);
1870 CView *pView = pFrame->GetActiveView();
1875 // Fail if view is of wrong kind
1876 // (this could occur with splitter windows, or additional
1877 // views on a single document
1878 if (! pView->IsKindOf(RUNTIME_CLASS(CFREDView)))
1881 return (CFREDView *) pView;
1884 /*void CFREDView::OnShipType0()
1886 cur_model_index = 1;
1889 void CFREDView::OnShipType1()
1891 cur_model_index = 2;
1894 void CFREDView::OnShipType2()
1896 cur_model_index = 3;
1899 void CFREDView::OnShipType3()
1901 cur_model_index = 4;
1904 void CFREDView::OnShipType4()
1906 cur_model_index = 5;
1909 void CFREDView::OnShipType5()
1911 cur_model_index = 6;
1914 void CFREDView::OnUpdateShipType1(CCmdUI* pCmdUI)
1916 pCmdUI->SetCheck(cur_model_index == 2);
1919 void CFREDView::OnUpdateShipType2(CCmdUI* pCmdUI)
1921 pCmdUI->SetCheck(cur_model_index == 3);
1924 void CFREDView::OnUpdateShipType3(CCmdUI* pCmdUI)
1926 pCmdUI->SetCheck(cur_model_index == 4);
1929 void CFREDView::OnUpdateShipType4(CCmdUI* pCmdUI)
1931 pCmdUI->SetCheck(cur_model_index == 5);
1934 void CFREDView::OnUpdateShipType5(CCmdUI* pCmdUI)
1936 pCmdUI->SetCheck(cur_model_index == 6);
1940 void CFREDView::OnUpdateShipType0(CCmdUI* pCmdUI)
1942 pCmdUI->SetCheck(cur_model_index == 1);
1946 void CFREDView::OnEditShipType6()
1948 cur_model_index = 7;
1952 void CFREDView::OnUpdateEditShipType6(CCmdUI* pCmdUI)
1954 pCmdUI->SetCheck(cur_model_index == 7);
1958 // following code added by MWA 09/04/96
1959 // Implements messages for popup menu built on the fly.
1960 // not sure how stable the code is, but appears to work for now.
1961 // id's for the menu items are simply the model numbers for
1962 // the ships. Shouldn't conflict with any other ID_* thingys.
1963 BOOL CFREDView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
1967 if (!pHandlerInfo) {
1968 if ((id >= SHIP_TYPES) && (id < SHIP_TYPES + Num_ship_types + 3)) {
1969 if (nCode == CN_COMMAND) {
1970 cur_model_index = id - SHIP_TYPES;
1971 m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
1973 } else if (nCode == CN_UPDATE_COMMAND_UI) {
1974 // Update UI element state
1975 ((CCmdUI*) pExtra)->SetCheck(cur_model_index + SHIP_TYPES == id);
1976 ((CCmdUI*) pExtra)->Enable(TRUE);
1983 return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
1986 void CFREDView::OnMiscStatistics()
1991 "Number of Objects: %d\n"
1992 "Number of Ships: %d\n"
1993 "Number of Wings: %d\n",
1994 num_objects, ship_get_num_ships(), num_wings);
1996 MessageBox(buf, "FRED Statistics");
1999 void CFREDView::OnUpdateChangeViewpointExternal(CCmdUI* pCmdUI)
2001 pCmdUI->SetCheck(!viewpoint);
2004 void CFREDView::OnChangeViewpointExternal()
2010 void CFREDView::OnUpdateChangeViewpointFollow(CCmdUI* pCmdUI)
2012 pCmdUI->SetCheck(viewpoint == 1);
2015 void CFREDView::OnChangeViewpointFollow()
2018 view_obj = cur_object_index;
2022 void CFREDView::OnEditorsGoals()
2024 CMissionGoalsDlg dlg;
2029 void CFREDView::OnSpeed1()
2032 set_physics_controls();
2035 void CFREDView::OnSpeed2()
2038 set_physics_controls();
2041 void CFREDView::OnSpeed3()
2044 set_physics_controls();
2047 void CFREDView::OnSpeed5()
2050 set_physics_controls();
2053 void CFREDView::OnSpeed8()
2056 set_physics_controls();
2059 void CFREDView::OnSpeed10()
2062 set_physics_controls();
2065 void CFREDView::OnSpeed50()
2068 set_physics_controls();
2071 void CFREDView::OnSpeed100()
2073 physics_speed = 100;
2074 set_physics_controls();
2077 void CFREDView::OnRot1()
2080 set_physics_controls();
2083 void CFREDView::OnRot2()
2086 set_physics_controls();
2089 void CFREDView::OnRot3()
2092 set_physics_controls();
2095 void CFREDView::OnRot4()
2098 set_physics_controls();
2101 void CFREDView::OnRot5()
2104 set_physics_controls();
2107 void CFREDView::OnUpdateSpeed1(CCmdUI* pCmdUI)
2109 pCmdUI->SetCheck(physics_speed == 1);
2112 void CFREDView::OnUpdateSpeed2(CCmdUI* pCmdUI)
2114 pCmdUI->SetCheck(physics_speed == 2);
2117 void CFREDView::OnUpdateSpeed3(CCmdUI* pCmdUI)
2119 pCmdUI->SetCheck(physics_speed == 3);
2122 void CFREDView::OnUpdateSpeed5(CCmdUI* pCmdUI)
2124 pCmdUI->SetCheck(physics_speed == 5);
2127 void CFREDView::OnUpdateSpeed8(CCmdUI* pCmdUI)
2129 pCmdUI->SetCheck(physics_speed == 8);
2132 void CFREDView::OnUpdateSpeed10(CCmdUI* pCmdUI)
2134 pCmdUI->SetCheck(physics_speed == 10);
2137 void CFREDView::OnUpdateSpeed50(CCmdUI* pCmdUI)
2139 pCmdUI->SetCheck(physics_speed == 50);
2142 void CFREDView::OnUpdateSpeed100(CCmdUI* pCmdUI)
2144 pCmdUI->SetCheck(physics_speed == 100);
2147 void CFREDView::OnUpdateRot1(CCmdUI* pCmdUI)
2149 pCmdUI->SetCheck(physics_rot == 2);
2152 void CFREDView::OnUpdateRot2(CCmdUI* pCmdUI)
2154 pCmdUI->SetCheck(physics_rot == 10);
2157 void CFREDView::OnUpdateRot3(CCmdUI* pCmdUI)
2159 pCmdUI->SetCheck(physics_rot == 25);
2162 void CFREDView::OnUpdateRot4(CCmdUI* pCmdUI)
2164 pCmdUI->SetCheck(physics_rot == 50);
2167 void CFREDView::OnUpdateRot5(CCmdUI* pCmdUI)
2169 pCmdUI->SetCheck(physics_rot == 100);
2172 void CFREDView::OnControlModeCamera()
2177 void CFREDView::OnUpdateControlModeCamera(CCmdUI* pCmdUI)
2179 pCmdUI->SetCheck(!Control_mode);
2182 void CFREDView::OnControlModeShip()
2187 void CFREDView::OnUpdateControlModeShip(CCmdUI* pCmdUI)
2189 pCmdUI->SetCheck(Control_mode == 1);
2192 void CFREDView::OnShowGridPositions()
2194 Show_grid_positions = !Show_grid_positions;
2195 theApp.write_ini_file();
2199 void CFREDView::OnUpdateShowGridPositions(CCmdUI* pCmdUI)
2201 pCmdUI->SetCheck(Show_grid_positions);
2204 void CFREDView::OnShowCoordinates()
2206 Show_coordinates = !Show_coordinates;
2207 theApp.write_ini_file();
2211 void CFREDView::OnUpdateShowCoordinates(CCmdUI* pCmdUI)
2213 pCmdUI->SetCheck(Show_coordinates);
2216 void CFREDView::OnSelect()
2221 void CFREDView::OnUpdateSelect(CCmdUI* pCmdUI)
2223 pCmdUI->SetCheck(!Editing_mode);
2226 void CFREDView::OnSelectAndMove()
2231 void CFREDView::OnUpdateSelectAndMove(CCmdUI* pCmdUI)
2233 pCmdUI->SetCheck(Editing_mode == 1);
2236 void CFREDView::OnSelectAndRotate()
2241 void CFREDView::OnUpdateSelectAndRotate(CCmdUI* pCmdUI)
2243 pCmdUI->SetCheck(Editing_mode == 2);
2246 void CFREDView::OnConstrainX()
2248 vm_vec_make(&Constraint, 1.0f, 0.0f, 0.0f);
2249 vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 1.0f);
2250 Single_axis_constraint = 1;
2253 void CFREDView::OnUpdateConstrainX(CCmdUI* pCmdUI)
2255 pCmdUI->SetRadio(Constraint.x && !Constraint.y && !Constraint.z);
2258 void CFREDView::OnConstrainY()
2260 vm_vec_make(&Constraint, 0.0f, 1.0f, 0.0f);
2261 vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 1.0f);
2262 Single_axis_constraint = 1;
2265 void CFREDView::OnUpdateConstrainY(CCmdUI* pCmdUI)
2267 pCmdUI->SetRadio(!Constraint.x && Constraint.y && !Constraint.z);
2270 void CFREDView::OnConstrainZ()
2272 vm_vec_make(&Constraint, 0.0f, 0.0f, 1.0f);
2273 vm_vec_make(&Anticonstraint, 1.0f, 1.0f, 0.0f);
2274 Single_axis_constraint = 1;
2277 void CFREDView::OnUpdateConstrainZ(CCmdUI* pCmdUI)
2279 pCmdUI->SetRadio(!Constraint.x && !Constraint.y && Constraint.z);
2282 void CFREDView::OnConstrainXz()
2284 vm_vec_make(&Constraint, 1.0f, 0.0f, 1.0f);
2285 vm_vec_make(&Anticonstraint, 0.0f, 1.0f, 0.0f);
2286 Single_axis_constraint = 0;
2289 void CFREDView::OnUpdateConstrainXz(CCmdUI* pCmdUI)
2291 pCmdUI->SetRadio(Constraint.x && !Constraint.y && Constraint.z);
2294 void CFREDView::OnConstrainXy()
2296 vm_vec_make(&Constraint, 1.0f, 1.0f, 0.0f);
2297 vm_vec_make(&Anticonstraint, 0.0f, 0.0f, 1.0f);
2298 Single_axis_constraint = 0;
2301 void CFREDView::OnUpdateConstrainXy(CCmdUI* pCmdUI)
2303 pCmdUI->SetRadio(Constraint.x && Constraint.y && !Constraint.z);
2306 void CFREDView::OnConstrainYz()
2308 vm_vec_make(&Constraint, 0.0f, 1.0f, 1.0f);
2309 vm_vec_make(&Anticonstraint, 1.0f, 0.0f, 0.0f);
2310 Single_axis_constraint = 0;
2313 void CFREDView::OnUpdateConstrainYz(CCmdUI* pCmdUI)
2315 pCmdUI->SetRadio(!Constraint.x && Constraint.y && Constraint.z);
2318 void CFREDView::OnSelectionLock()
2320 Selection_lock = !Selection_lock;
2323 void CFREDView::OnUpdateSelectionLock(CCmdUI* pCmdUI)
2325 pCmdUI->SetCheck(Selection_lock);
2328 void CFREDView::OnLButtonDblClk(UINT nFlags, CPoint point)
2330 CView::OnLButtonDblClk(nFlags, point);
2331 if (Cursor_over != -1) {
2332 switch (Objects[Cursor_over].type) {
2340 OnEditorsWaypoint();
2344 } else if (Briefing_dialog)
2345 Fixed_briefing_size = !Fixed_briefing_size;
2348 void CFREDView::OnDoubleFineGridlines()
2350 double_fine_gridlines = !double_fine_gridlines;
2351 maybe_create_new_grid(The_grid, &eye_pos, &eye_orient, 1);
2352 theApp.write_ini_file();
2356 void CFREDView::OnUpdateDoubleFineGridlines(CCmdUI* pCmdUI)
2358 pCmdUI->SetCheck(double_fine_gridlines);
2361 void CFREDView::OnShowDistances()
2363 Show_distances = !Show_distances;
2364 theApp.write_ini_file();
2368 void CFREDView::OnUpdateShowDistances(CCmdUI* pCmdUI)
2370 pCmdUI->SetCheck(Show_distances);
2373 void CFREDView::OnUniversalHeading()
2375 Universal_heading = !Universal_heading;
2378 void CFREDView::OnUpdateUniversalHeading(CCmdUI* pCmdUI)
2380 pCmdUI->SetCheck(Universal_heading);
2383 void CFREDView::OnFlyingControls()
2385 Flying_controls_mode = !Flying_controls_mode;
2388 void CFREDView::OnUpdateFlyingControls(CCmdUI* pCmdUI)
2390 pCmdUI->SetCheck(Flying_controls_mode);
2393 void CFREDView::OnRotateLocally()
2395 Group_rotate = !Group_rotate;
2398 void CFREDView::OnUpdateRotateLocally(CCmdUI* pCmdUI)
2400 pCmdUI->SetCheck(!Group_rotate);
2403 void CFREDView::OnSelectList()
2410 // position camera to view all objects on the screen at once. Doesn't change orientation.
2411 void view_universe(int just_marked)
2413 int i, max = 0, flags[MAX_OBJECTS];
2414 float dist, largest = 20.0f;
2415 vector center, p1, p2; // center of all the objects collectively
2419 for (i=0; i<MAX_OBJECTS; i++)
2423 ptr = &Objects[cur_object_index];
2425 ptr = GET_FIRST(&obj_used_list);
2427 p1.x = p2.x = ptr->pos.x;
2428 p1.y = p2.y = ptr->pos.y;
2429 p1.z = p2.z = ptr->pos.z;
2431 ptr = GET_FIRST(&obj_used_list);
2432 while (ptr != END_OF_LIST(&obj_used_list)) {
2433 if (!just_marked || (ptr->flags & OF_MARKED)) {
2435 if (center.x < p1.x)
2437 if (center.x > p2.x)
2439 if (center.y < p1.y)
2441 if (center.y > p2.y)
2443 if (center.z < p1.z)
2445 if (center.z > p2.z)
2449 ptr = GET_NEXT(ptr);
2452 vm_vec_avg(¢er, &p1, &p2);
2453 ptr = GET_FIRST(&obj_used_list);
2454 while (ptr != END_OF_LIST(&obj_used_list)) {
2455 if (!just_marked || (ptr->flags & OF_MARKED)) {
2456 dist = vm_vec_dist_squared(¢er, &ptr->pos);
2460 flags[OBJ_INDEX(ptr)] = 1; // flag object as needing on-screen check
2461 if (OBJ_INDEX(ptr) > max)
2462 max = OBJ_INDEX(ptr);
2465 ptr = GET_NEXT(ptr);
2468 dist = fl_sqrt(largest) + 1.0f;
2469 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2470 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2472 ptr = GET_FIRST(&obj_used_list);
2473 while (ptr != END_OF_LIST(&obj_used_list)) {
2474 if (!just_marked || (ptr->flags & OF_MARKED)) {
2475 g3_rotate_vertex(&v, &ptr->pos);
2476 Assert(!(v.codes & CC_BEHIND));
2477 if (g3_project_vertex(&v) & PF_OVERFLOW)
2480 while (v.codes & CC_OFF) { // is point off screen?
2481 dist += 5.0f; // zoom out a little and check again.
2482 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2483 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2484 g3_rotate_vertex(&v, &ptr->pos);
2485 if (g3_project_vertex(&v) & PF_OVERFLOW)
2490 ptr = GET_NEXT(ptr);
2494 vm_vec_scale_add(&view_pos, ¢er, &view_orient.fvec, -dist);
2495 g3_set_view_matrix(&view_pos, &view_orient, 0.5f);
2499 void CFREDView::cycle_constraint()
2501 if (Single_axis_constraint) {
2504 else if (Constraint.y)
2506 else if (Constraint.z)
2512 else if (!Constraint.y)
2514 else if (!Constraint.z)
2519 void CFREDView::OnZoomExtents()
2524 void CFREDView::OnZoomSelected()
2526 if (query_valid_object()) {
2530 vm_vec_scale_add(&view_pos, &Objects[cur_object_index].pos, &view_orient.fvec, Objects[cur_object_index].radius * -3.0f);
2536 void CFREDView::OnUpdateZoomSelected(CCmdUI* pCmdUI)
2538 pCmdUI->Enable(query_valid_object());
2541 void CFREDView::OnFormWing()
2544 FREDDoc_ptr->autosave("form wing");
2547 void CFREDView::OnUpdateFormWing(CCmdUI* pCmdUI)
2552 if (query_valid_object()) {
2553 ptr = GET_FIRST(&obj_used_list);
2554 while (ptr != END_OF_LIST(&obj_used_list)) {
2555 if (ptr->flags & OF_MARKED) {
2556 if (ptr->type == OBJ_SHIP)
2557 switch (ship_query_general_type(ptr->instance))
2559 case SHIP_TYPE_FIGHTER_BOMBER:
2560 case SHIP_TYPE_CRUISER:
2561 case SHIP_TYPE_AWACS:
2562 case SHIP_TYPE_GAS_MINER:
2563 case SHIP_TYPE_CORVETTE:
2564 case SHIP_TYPE_FREIGHTER:
2565 case SHIP_TYPE_CAPITAL:
2566 case SHIP_TYPE_TRANSPORT:
2570 if (ptr->type == OBJ_START)
2574 ptr = GET_NEXT(ptr);
2578 pCmdUI->Enable(count > 0);
2581 int query_single_wing_marked()
2585 if (!query_valid_object())
2591 i = Wings[cur_wing].wave_count;
2592 if (Marked != i) // does marked object count match number of ships in wing?
2596 obj = wing_objects[cur_wing][i];
2597 if ((Objects[obj].type != OBJ_SHIP) && (Objects[obj].type != OBJ_START))
2598 Error(LOCATION, "Invalid objects detected in wing \"%s\"", Wings[cur_wing].name);
2600 // if (Ships[Objects[obj].instance].wingnum != cur_wing)
2602 Assert(Ships[Objects[obj].instance].wingnum == cur_wing);
2603 if (!(Objects[obj].flags & OF_MARKED)) // ensure all ships in wing.are marked
2610 void CFREDView::OnDisbandWing()
2612 if (query_single_wing_marked()) {
2613 remove_wing(cur_wing);
2614 FREDDoc_ptr->autosave("wing disband");
2617 MessageBox("One and only one wing must be selected for this operation");
2620 void CFREDView::OnUpdateDisbandWing(CCmdUI* pCmdUI)
2622 pCmdUI->Enable(query_single_wing_marked());
2625 void CFREDView::OnShowHorizon()
2627 Show_horizon = !Show_horizon;
2628 theApp.write_ini_file();
2632 void CFREDView::OnUpdateShowHorizon(CCmdUI* pCmdUI)
2634 pCmdUI->SetCheck(Show_horizon);
2637 void CFREDView::OnEditorsWing()
2641 Assert(Wing_editor_dialog.GetSafeHwnd());
2642 if (!Show_sexp_help)
2643 adjust = -SEXP_HELP_BOX_SIZE;
2645 if (!theApp.init_window(&Wing_wnd_data, &Wing_editor_dialog, adjust))
2648 Wing_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
2649 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2650 Wing_editor_dialog.ShowWindow(SW_RESTORE);
2653 void CFREDView::OnEditorsPlayer()
2655 player_start_editor dlg;
2660 void CFREDView::OnEditorsOrient()
2667 void CFREDView::OnEditorsEvents()
2669 if (Message_editor_dlg) {
2670 MessageBox("You must close the message editor before opening the event editor");
2674 if (!Event_editor_dlg) {
2675 Event_editor_dlg = new event_editor;
2676 Event_editor_dlg->Create(event_editor::IDD);
2679 Event_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2680 Event_editor_dlg->ShowWindow(SW_RESTORE);
2683 void CFREDView::OnUpdateEditorsOrient(CCmdUI* pCmdUI)
2685 pCmdUI->Enable(query_valid_object());
2688 void CFREDView::OnEditorsMessage()
2690 if (Event_editor_dlg) {
2691 MessageBox("You must close the event editor before opening the message editor");
2695 if (!Message_editor_dlg) {
2696 Message_editor_dlg = new CMessageEditorDlg;
2697 Message_editor_dlg->Create(CMessageEditorDlg::IDD);
2700 Message_editor_dlg->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2701 Message_editor_dlg->ShowWindow(SW_RESTORE);
2704 void CFREDView::OnEditorsStarfield()
2706 starfield_editor dlg;
2711 void CFREDView::place_background_bitmap(vector v)
2715 void CFREDView::OnEditorsBgBitmaps()
2717 if (!Bg_bitmap_dialog) {
2718 Bg_bitmap_dialog = new bg_bitmap_dlg;
2719 Bg_bitmap_dialog->create();
2722 Bg_bitmap_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
2723 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2724 Bg_bitmap_dialog->ShowWindow(SW_RESTORE);
2727 void CFREDView::OnEditorsReinforcement()
2729 reinforcement_editor_dlg dlg;
2734 void CFREDView::OnErrorChecker()
2738 z = global_error_check();
2740 MessageBox("No errors were detected in this mission", "Woohoo!");
2742 for (z=0; z<obj_count; z++)
2749 int CFREDView::global_error_check()
2751 char buf[256], *str;
2752 int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
2755 int starting_orders;
2758 if ( The_mission.game_type & MISSION_TYPE_MULTI )
2761 // if (!stricmp(The_mission.name, "Untitled"))
2762 // if (error("You haven't given this mission a title yet.\nThis is done from the Mission Specs Editor (Shift-N)."))
2765 // cycle though all the objects and verify every possible aspect of them
2767 ptr = GET_FIRST(&obj_used_list);
2768 while (ptr != END_OF_LIST(&obj_used_list)) {
2769 names[obj_count] = NULL;
2770 flags[obj_count] = 0;
2772 if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
2773 if (i < 0 || i >= MAX_SHIPS){
2774 return internal_error("An object has an illegal ship index");
2777 z = Ships[i].ship_info_index;
2778 if ((z < 0) || (z >= Num_ship_types)){
2779 return internal_error("A ship has an illegal class");
2782 if (ptr->type == OBJ_START) {
2784 if (!(Ship_info[z].flags & SIF_PLAYER_SHIP)) {
2785 ptr->type = OBJ_SHIP;
2788 if (error("Invalid ship type for a player. Ship has been reset to non-player ship.")){
2793 for (n=count=0; n<MAX_PRIMARY_BANKS; n++){
2794 if (Ships[i].weapons.primary_bank_weapons[n] >= 0){
2800 if (error("Player \"%s\" has no primary weapons. Should have at least 1", Ships[i].ship_name)){
2805 for (n=count=0; n<MAX_SECONDARY_BANKS; n++){
2806 if (Ships[i].weapons.secondary_bank_weapons[n] >= 0){
2812 if (error("Player \"%s\" has no secondary weapons. Should have at least 1", Ships[i].ship_name)){
2818 if (Ships[i].objnum != OBJ_INDEX(ptr)){
2819 return internal_error("Object/ship references are corrupt");
2822 names[obj_count] = Ships[i].ship_name;
2823 wing = Ships[i].wingnum;
2824 if (wing >= 0) { // ship is part of a wing, so check this
2825 if (wing < 0 || wing >= MAX_WINGS){ // completely out of range?
2826 return internal_error("A ship has an illegal wing index");
2829 j = Wings[wing].wave_count;
2831 return internal_error("A ship is in a non-existant wing");
2834 if (j < 0 || j > MAX_SHIPS_PER_WING){
2835 return internal_error("Invalid number of ships in wing \"%s\"", Wings[z].name);
2839 if (wing_objects[wing][j] == OBJ_INDEX(ptr)){ // look for object in wing's table
2845 return internal_error("Ship/wing references are corrupt");
2849 if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (Ships[i].hotkey >= 0) ){
2850 if (error("Ship flagged as \"destroy before mission start\" has a hotkey assignment")){
2855 if ( (Ships[i].flags & SF_KILL_BEFORE_MISSION) && (ptr->type == OBJ_START) ){
2856 if (error("Player start flagged as \"destroy before mission start\"")){
2860 } else if (ptr->type == OBJ_WAYPOINT) {
2861 j = i / 65536; // waypoint path number
2862 z = i & 0xffff; // waypoint number in path
2863 if (j < 0 || j >= Num_waypoint_lists){
2864 return internal_error("Object references an illegal waypoint path number");
2867 if (z >= Waypoint_lists[j].count){
2868 return internal_error("Object references an illegal waypoint number in path");
2871 sprintf(buf, "%s:%d", Waypoint_lists[j].name, z + 1);
2872 names[obj_count] = new char[strlen(buf) + 1];
2873 strcpy(names[obj_count], buf);
2874 flags[obj_count] = 1;
2875 } else if (ptr->type == OBJ_POINT) {
2876 if (!Briefing_dialog){
2877 return internal_error("Briefing icon detected when not in briefing edit mode");
2879 } else if (ptr->type == OBJ_JUMP_NODE) {
2880 if (i < 0 || i >= Num_jump_nodes){
2881 return internal_error("Object has illegal jump node index");
2884 return internal_error("An unknown object type (%d) was detected", ptr->type);
2887 for (i=0; i<obj_count; i++){
2888 if (names[i] && names[obj_count]){
2889 if (!stricmp(names[i], names[obj_count])){
2890 return internal_error("Duplicate object names (%s)", names[i]);
2896 ptr = GET_NEXT(ptr);
2899 if (t != Player_starts){
2900 return internal_error("Total number of player ships is incorrect");
2903 if (obj_count != num_objects){
2904 return internal_error("num_objects is incorrect");
2908 for (i=0; i<MAX_SHIPS; i++) {
2909 if (Ships[i].objnum >= 0) { // is ship being used?
2911 if (!query_valid_object(Ships[i].objnum)){
2912 return internal_error("Ship uses an unused object");
2915 z = Objects[Ships[i].objnum].type;
2916 if ((z != OBJ_SHIP) && (z != OBJ_START)){
2917 return internal_error("Object should be a ship, but isn't");
2920 if (fred_check_sexp(Ships[i].arrival_cue, OPR_BOOL, "arrival cue of ship \"%s\"", Ships[i].ship_name)){
2924 if (fred_check_sexp(Ships[i].departure_cue, OPR_BOOL, "departure cue of ship \"%s\"", Ships[i].ship_name)){
2928 if (Ships[i].arrival_location != ARRIVE_AT_LOCATION) {
2929 if (Ships[i].arrival_anchor < 0){
2930 if (error("Ship \"%s\" requires a valid arrival target", Ships[i].ship_name)){
2936 if (Ships[i].departure_location != DEPART_AT_LOCATION) {
2937 if (Ships[i].departure_anchor < 0){
2938 if (error("Ship \"%s\" requires a valid departure target", Ships[i].ship_name)){
2944 ai = Ships[i].ai_index;
2945 if (ai < 0 || ai >= MAX_AI_INFO){
2946 return internal_error("AI index out of range for ship \"%s\"", Ships[i].ship_name);
2949 if (Ai_info[ai].shipnum != i){
2950 return internal_error("AI/ship references are corrupt");
2953 if ((str = error_check_initial_orders(Ai_info[ai].goals, i, -1))>0) {
2955 return internal_error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str + 1);
2956 else if (*str == '!')
2958 else if (error("Initial orders error for ship \"%s\"\n\n%s", Ships[i].ship_name, str))
2962 obj = Ai_info[ai].dock_objnum;
2964 if (!query_valid_object(obj)){
2965 return internal_error("Ship \"%s\" initially docked with non-existant ship", Ships[i].ship_name);
2968 if (Objects[obj].type != OBJ_SHIP && Objects[obj].type != OBJ_START){
2969 return internal_error("Ship \"%s\" initially docked with non-ship object", Ships[i].ship_name);
2972 ship = get_ship_from_obj(obj);
2973 if (!ship_docking_valid(i, ship) && !ship_docking_valid(ship, i)){
2974 return internal_error("Docking illegal between \"%s\" and \"%s\" (initially docked)", Ships[i].ship_name, Ships[ship].ship_name);
2977 z = get_docking_list(Ships[i].modelnum);
2978 point = Ai_info[ai].dock_index;
2979 if (point < 0 || point >= z){
2980 internal_error("Invalid docker point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
2983 z = get_docking_list(Ships[ship].modelnum);
2984 point = Ai_info[ai].dockee_index;
2985 if (point < 0 || point >= z){
2986 internal_error("Invalid dockee point (\"%s\" initially docked with \"%s\")", Ships[i].ship_name, Ships[ship].ship_name);
2992 if (count != ship_get_num_ships()){
2993 return internal_error("num_ships is incorrect");
2997 for (i=0; i<MAX_WINGS; i++) {
2999 j = Wings[i].wave_count;
3000 if (j) { // is wing being used?
3002 if (j < 0 || j > MAX_SHIPS_PER_WING){
3003 return internal_error("Invalid number of ships in wing \"%s\"", Wings[i].name);
3007 obj = wing_objects[i][j];
3008 if (obj < 0 || obj >= MAX_OBJECTS){
3009 return internal_error("Wing_objects has an illegal object index");
3012 if (!query_valid_object(obj)){
3013 return internal_error("Wing_objects references an unused object");
3016 // Now, at this point, we can assume several things. We have a valid object because
3017 // we passed query_valid_object(), and all valid objects were already checked above,
3018 // so this object has valid information, such as the instance.
3020 if ((Objects[obj].type == OBJ_SHIP) || (Objects[obj].type == OBJ_START)) {
3021 ship = Objects[obj].instance;
3022 sprintf(buf, "%s %d", Wings[i].name, j + 1);
3023 if (stricmp(buf, Ships[ship].ship_name)){
3024 return internal_error("Ship \"%s\" in wing should be called \"%s\"", Ships[ship].ship_name, buf);
3027 switch (ship_query_general_type(ship))
3029 case SHIP_TYPE_FIGHTER_BOMBER:
3030 case SHIP_TYPE_CRUISER:
3031 case SHIP_TYPE_AWACS:
3032 case SHIP_TYPE_GAS_MINER:
3033 case SHIP_TYPE_CORVETTE:
3034 case SHIP_TYPE_FREIGHTER:
3035 case SHIP_TYPE_CAPITAL:
3036 case SHIP_TYPE_TRANSPORT:
3037 case SHIP_TYPE_SUPERCAP:
3041 if (error("Ship \"%s\" is an illegal type to be in a wing", Ships[ship].ship_name)){
3046 return internal_error("Wing_objects of \"%s\" references an illegal object type", Wings[i].name);
3049 if (Ships[ship].wingnum != i){
3050 return internal_error("Wing/ship references are corrupt");
3053 if (ship != Wings[i].ship_index[j]){
3054 return internal_error("Ship/wing references are corrupt");
3058 team = Ships[ship].team;
3059 } else if (team != Ships[ship].team && team < 999){
3060 if (error("ship teams mixed within same wing (\"%s\")", Wings[i].name)){
3066 if ((Wings[i].special_ship < 0) || (Wings[i].special_ship >= Wings[i].wave_count)){
3067 return internal_error("Special ship out of range for \"%s\"", Wings[i].name);
3070 if (Wings[i].num_waves < 0){
3071 return internal_error("Number of waves for \"%s\" is negative", Wings[i].name);
3074 if ((Wings[i].threshold < 0) || (Wings[i].threshold >= Wings[i].wave_count)){
3075 return internal_error("Threshold for \"%s\" is invalid", Wings[i].name);
3078 if (Wings[i].threshold + Wings[i].wave_count > MAX_SHIPS_PER_WING) {
3079 Wings[i].threshold = MAX_SHIPS_PER_WING - Wings[i].wave_count;
3080 if(error("Threshold for wing \"%s\" is higher than allowed. Reset to %d", Wings[i].name, Wings[i].threshold)){
3085 for (j=0; j<obj_count; j++){
3087 if (!stricmp(names[j], Wings[i].name)){
3088 return internal_error("Wing name is also used by an object (%s)", names[j]);
3093 if(fred_check_sexp(Wings[i].arrival_cue, OPR_BOOL, "arrival cue of wing \"%s\"", Wings[i].name)){
3097 if(fred_check_sexp(Wings[i].departure_cue, OPR_BOOL, "departure cue of wing \"%s\"", Wings[i].name)){
3101 if (Wings[i].arrival_location != ARRIVE_AT_LOCATION) {
3102 if (Wings[i].arrival_anchor < 0)
3103 if (error("Wing \"%s\" requires a valid arrival target", Wings[i].name))
3107 if (Wings[i].departure_location != DEPART_AT_LOCATION) {
3108 if (Wings[i].departure_anchor < 0)
3109 if (error("Wing \"%s\" requires a valid departure target", Wings[i].name))
3113 if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i))>0) {
3115 return internal_error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str + 1);
3116 else if (*str == '!')
3118 else if (error("Initial orders error for wing \"%s\"\n\n%s", Wings[i].name, str))
3125 if (count != num_wings){
3126 return internal_error("num_wings is incorrect");
3129 for (i=0; i<Num_waypoint_lists; i++) {
3130 for (z=0; z<obj_count; z++){
3132 if (!stricmp(names[z], Waypoint_lists[i].name)){
3133 return internal_error("Waypoint path name is also used by an object (%s)", names[z]);
3138 j = Waypoint_lists[i].count;
3140 sprintf(buf, "%s:%d", Waypoint_lists[i].name, j + 1);
3141 for (z=0; z<obj_count; z++){
3143 if (!stricmp(names[z], buf)){
3149 if (z == obj_count){
3150 return internal_error("Waypoint \"%s\" not linked to an object", buf);
3155 if (Player_starts > MAX_PLAYERS){
3156 return internal_error("Number of player starts exceeds max limit");
3159 if (!multi && (Player_starts > 1)){
3160 if (error("Multiple player starts exist, but this is a single player mission")){
3165 if (Num_reinforcements > MAX_REINFORCEMENTS){
3166 return internal_error("Number of reinforcements exceeds max limit");
3169 for (i=0; i<Num_reinforcements; i++) {
3171 for (ship=0; ship<MAX_SHIPS; ship++){
3172 if ((Ships[ship].objnum >= 0) && !stricmp(Ships[ship].ship_name, Reinforcements[i].name)) {
3178 for (wing=0; wing<MAX_WINGS; wing++){
3179 if (Wings[wing].wave_count && !stricmp(Wings[wing].name, Reinforcements[i].name)) {
3186 return internal_error("Reinforcement name not found in ships or wings");
3190 /* for (i=0; i<num_messages; i++) {
3191 if (Messages[i].num_times < 0)
3192 return internal_error("Number of times to play message is negative");
3194 z = Messages[i].who_from;
3195 if (z < -1 || z >= MAX_SHIPS) // hacked! -1 should be illegal..
3196 return internal_error("Message originator index is out of range");
3198 if (Ships[z].objnum == -1)
3199 return internal_error("Message originator points to nonexistant ship");
3201 if (fred_check_sexp(Messages[i].sexp, OPR_BOOL,
3202 "Message formula from \"%s\"", Ships[Messages[i].who_from].ship_name))
3206 Assert((Player_start_shipnum >= 0) && (Player_start_shipnum < MAX_SHIPS) && (Ships[Player_start_shipnum].objnum >= 0));
3207 i = global_error_check_player_wings(multi);
3212 for (i=0; i<Num_mission_events; i++){
3213 if (fred_check_sexp(Mission_events[i].formula, OPR_NULL, "mission event \"%s\"", Mission_events[i].name)){
3218 for (i=0; i<Num_goals; i++){
3219 if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission goal \"%s\"", Mission_goals[i].name)){
3224 for ( bs = 0; bs < Num_teams; bs++ ) {
3225 for (s=0; s<Briefings[bs].num_stages; s++) {
3226 sp = &Briefings[bs].stages[s];
3228 for (i=0; i<t-1; i++){
3229 for (j=i+1; j<t; j++) {
3230 if ((sp->icons[i].id > 0) && (sp->icons[i].id == sp->icons[j].id)){
3231 if (error("Duplicate icon IDs %d in briefing stage %d", sp->icons[i].id, s + 1)){
3240 for ( j = 0; j < Num_teams; j++ ) {
3241 for (i=0; i<Debriefings[j].num_stages; i++) {
3242 if (fred_check_sexp(Debriefings[j].stages[i].formula, OPR_BOOL, "debriefing stage %d", i + 1)){
3248 // for all wings, be sure that the orders accepted for all ships are the same for all ships
3250 starting_orders = -1;
3251 for (i=0; i<MAX_WINGS; i++) {
3252 int default_orders, starting_wing;
3254 if ( !Wings[i].wave_count ){
3258 // determine if this wing is a starting wing of the player
3260 for ( j = 0; j < MAX_STARTING_WINGS; j++ ) {
3261 if ( !stricmp( Wings[i].name, Starting_wing_names[j]) ){
3265 if ( j == MAX_STARTING_WINGS ){
3269 // first, be sure this isn't a reinforcement wing.
3270 if ( starting_wing && (Wings[i].flags & WF_REINFORCEMENT) ) {
3271 if ( error("Starting Wing %s marked as reinforcement. This wing\nshould either be renamed, or unmarked as reinforcement.", Wings[i].name) ){
3277 for ( j = 0; j < Wings[i].wave_count; j++ ) {
3280 orders = Ships[Wings[i].ship_index[j]].orders_accepted;
3282 default_orders = orders;
3283 } else if ( default_orders != orders ) {
3284 if (error("Wing %s has ships with different player orders which\nare ignored. They must all be the same", Wings[i].name ) ){
3290 // make sure that these ignored orders are the same for all starting wings of the player
3291 if ( starting_wing ) {
3292 if ( starting_orders == -1 ) {
3293 starting_orders = default_orders;
3295 if ( starting_orders != default_orders ) {
3296 if ( error("Player starting wing %s has orders which don't match other starting wings\n", Wings[i].name) ){
3304 if (Num_jump_nodes < 0 || Num_jump_nodes > MAX_JUMP_NODES){
3305 return internal_error("Jump node count is illegal");
3308 fred_check_message_personas();
3313 int CFREDView::global_error_check_mixed_player_wing(int w)
3315 int i, s, species = -1, mixed = 0;
3317 for (i=0; i<Wings[w].wave_count; i++) {
3318 s = Wings[w].ship_index[i];
3320 species = Ship_info[Ships[s].ship_info_index].species;
3321 else if (Ship_info[Ships[s].ship_info_index].species != species)
3326 if (error("%s wing must all be of the same species", Wings[w].name))
3332 int CFREDView::global_error_check_player_wings(int multi)
3334 int i, z, alpha, beta, gamma, zeta, err, alpha_count, zeta_count;
3337 z = Ships[Player_start_shipnum].wingnum;
3338 alpha = wing_name_lookup("alpha", 1);
3339 beta = wing_name_lookup("beta", 1);
3340 gamma = wing_name_lookup("gamma", 1);
3341 zeta = wing_name_lookup( "zeta", 1 );
3344 free_sexp2(Wings[alpha].arrival_cue);
3345 Wings[alpha].arrival_cue = Locked_sexp_true;
3348 if (multi && (alpha < 0)){
3349 if (error("Alpha wing is required for multiplayer missions")){
3354 // Check to be sure that any player starting wing doesn't have > 1 wave for multiplayer
3356 if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
3357 if ( alpha && (Wings[alpha].num_waves > 1) ) {
3358 error("Alpha wing must contain only 1 wave.\nThis change has been made for you.");
3359 Wings[alpha].num_waves = 1;
3362 if ( zeta && (Wings[zeta].num_waves > 1) ) {
3363 error("Zeta wing must contain only 1 wave.\nThis change has been made for you.");
3364 Wings[zeta].num_waves = 1;
3369 if ( alpha && (Wings[alpha].num_waves > 1) ) {
3370 error("Alpha wing must contain only 1 wave.\nThis change has been made for you.");
3371 Wings[alpha].num_waves = 1;
3374 if ( beta && (Wings[beta].num_waves > 1) ) {
3375 error("Beta wing must contain only 1 wave.\nThis change has been made for you.");
3376 Wings[beta].num_waves = 1;
3379 if ( gamma && (Wings[gamma].num_waves > 1) ) {
3380 error("Gamma wing must contain only 1 wave.\nThis change has been made for you.");
3381 Wings[gamma].num_waves = 1;
3387 // if not a multiplayer misison, or a coop multiplayer mission, then do "normal"
3388 // wing name checking.
3389 if ( !multi || (The_mission.game_type & MISSION_TYPE_MULTI_COOP) ) {
3390 if (((alpha >= 0) || (z >= 0)) && (alpha != z)){
3391 if (error("Player start is not in Alpha wing")){
3396 if ((beta >= 0) && (alpha < 0)){
3397 if (error("Alpha wing required, but not present")){
3402 if ((gamma >= 0) && (beta < 0)){
3403 if (error("Beta wing required, but not present")){
3408 if ((alpha >= 0) && (Wings[alpha].wave_count > 4)){
3409 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3414 if ((beta >= 0) && (Wings[beta].wave_count > 4)){
3415 if (error("Beta wing has too many ships. Should only have 4 max.")){
3420 if ((gamma >= 0) && (Wings[gamma].wave_count > 4)){
3421 if (error("Gamma wing has too many ships. Should only have 4 max.")){
3426 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3427 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3431 } else if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
3433 if (error("Zeta wing is required for multiplayer team vs. team missions")){
3438 if ( Wings[alpha].wave_count > 4 ){
3439 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3444 if ( Wings[zeta].wave_count > 4 ) {
3445 if (error("Zeta wing has too many ships. Should only have 4 max.")){
3450 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3451 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3456 if ((zeta >= 0) && Wings[zeta].arrival_delay){
3457 if (error("Zeta wing shouldn't have a non-zero arrival delay")){
3461 } else if ( The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT ) {
3462 if ( Wings[alpha].wave_count > 4 ) {
3463 if (error("Alpha wing has too many ships. Should only have 4 max.")){
3468 if ((alpha >= 0) && Wings[alpha].arrival_delay){
3469 if (error("Alpha wing shouldn't have a non-zero arrival delay")){
3474 error("Unknown game type: %d", The_mission.game_type);
3480 if (global_error_check_mixed_player_wing(alpha)){
3486 if (global_error_check_mixed_player_wing(beta)){
3492 if (global_error_check_mixed_player_wing(gamma)){
3498 if (global_error_check_mixed_player_wing(zeta)){
3504 alpha_count = zeta_count = 0;
3505 ptr = GET_FIRST(&obj_used_list);
3506 while (ptr != END_OF_LIST(&obj_used_list)) {
3509 if (ptr->type == OBJ_START) {
3510 z = Ships[i].wingnum;
3516 } else if (z == zeta){
3520 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) {
3521 if ((z != alpha) && (z != zeta)){
3525 if ((z != alpha) && (z != beta) && (z != gamma)){
3532 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) {
3533 if (error("Player \"%s\" should be part Alpha or Zeta wing", Ships[i].ship_name)){
3537 if (error("Player \"%s\" should be part Alpha, Beta or Gamma wing", Ships[i].ship_name)){
3544 ptr = GET_NEXT(ptr);
3547 if ((alpha >= 0) && !alpha_count){
3548 if (error("Alpha wing doesn't contain any players, which it should.")){
3553 if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS){
3554 if ((zeta >= 0) && !zeta_count){
3555 if (error("Zeta wing doesn't contain any players, which it should.")){
3564 int CFREDView::error(char *msg, ...)
3569 va_start(args, msg);
3570 vsprintf(buf, msg, args);
3574 if (MessageBox(buf, "Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
3580 int CFREDView::internal_error(char *msg, ...)
3585 va_start(args, msg);
3586 vsprintf(buf, msg, args);
3594 sprintf(buf2, "%s\n\nThis is an internal error. Please let Jason\n"
3595 "know about this so he can fix it. Click cancel to debug.", buf);
3597 if (MessageBox(buf2, "Internal Error", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
3598 Int3(); // drop to debugger so the problem can be analyzed.
3601 MessageBox(buf, "Error", MB_OK | MB_ICONEXCLAMATION);
3607 int CFREDView::fred_check_sexp(int sexp, int type, char *msg, ...)
3609 char buf[512], buf2[2048], buf3[4096];
3610 int err = 0, z, faulty_node;
3613 va_start(args, msg);
3614 vsprintf(buf, msg, args);
3620 z = check_sexp_syntax(sexp, type, 1, &faulty_node);
3624 convert_sexp_to_string(sexp, buf2, SEXP_ERROR_CHECK_MODE);
3625 sprintf(buf3, "Error in %s: %s\n\nIn sexpression: %s\n(Error appears to be: %s)",
3626 buf, sexp_error_message(z), buf2, Sexp_nodes[faulty_node].text);
3628 if (z < 0 && z > -100)
3632 return internal_error(buf3);
3640 void CFREDView::OnEditorsWaypoint()
3644 Assert(Waypoint_editor_dialog.GetSafeHwnd());
3645 if (!Show_sexp_help)
3646 adjust = -SEXP_HELP_BOX_SIZE;
3648 if (!theApp.init_window(&Waypoint_wnd_data, &Waypoint_editor_dialog))
3651 Waypoint_editor_dialog.SetWindowPos(&wndTop, 0, 0, 0, 0,
3652 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
3653 Waypoint_editor_dialog.ShowWindow(SW_RESTORE);
3656 char *error_check_initial_orders(ai_goal *goals, int ship, int wing)
3659 int i, j, num, flag, found, inst, team, team2;
3663 source = Ships[ship].ship_name;
3664 team = Ships[ship].team;
3665 for (i=0; i<MAX_AI_GOALS; i++)
3666 if (!ai_query_goal_valid(ship, goals[i].ai_mode)) {
3667 if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode), source))
3673 Assert(Wings[wing].wave_count > 0);
3674 source = Wings[wing].name;
3675 team = Ships[Objects[wing_objects[wing][0]].instance].team;
3676 for (j=0; j<Wings[wing].wave_count; j++)
3677 for (i=0; i<MAX_AI_GOALS; i++)
3678 if (!ai_query_goal_valid(Wings[wing].ship_index[j], goals[i].ai_mode)) {
3679 if (Fred_view_wnd->error("Order \"%s\" isn't allowed for ship \"%s\"", get_order_name(goals[i].ai_mode),
3680 Ships[Wings[wing].ship_index[j]].ship_name))
3685 for (i=0; i<MAX_AI_GOALS; i++) {
3686 switch (goals[i].ai_mode) {
3688 case AI_GOAL_CHASE_ANY:
3689 case AI_GOAL_UNDOCK:
3690 case AI_GOAL_KEEP_SAFE_DISTANCE:
3691 case AI_GOAL_PLAY_DEAD:
3696 case AI_GOAL_WAYPOINTS:
3697 case AI_GOAL_WAYPOINTS_ONCE:
3703 return "Wings can't dock";
3706 case AI_GOAL_DESTROY_SUBSYSTEM:
3709 case AI_GOAL_DISARM_SHIP:
3710 case AI_GOAL_DISABLE_SHIP:
3711 case AI_GOAL_EVADE_SHIP:
3712 case AI_GOAL_STAY_NEAR_SHIP:
3713 case AI_GOAL_IGNORE:
3717 case AI_GOAL_CHASE_WING:
3718 case AI_GOAL_GUARD_WING:
3722 case AI_GOAL_STAY_STILL:
3727 return "*Invalid goal type";
3732 if (*goals[i].ship_name == '<')
3733 return "Invalid target";
3735 if (!stricmp(goals[i].ship_name, source))
3737 return "Target of ship's goal is itself";
3739 return "Target of wing's goal is itself";
3743 if (flag == 1) { // target waypoint required
3744 for (j=0; j<Num_waypoint_lists; j++)
3745 if (!stricmp(goals[i].ship_name, Waypoint_lists[j].name))
3749 return "*Invalid target waypoint path name";
3751 } else if (flag == 2) { // target ship required
3752 ptr = GET_FIRST(&obj_used_list);
3753 while (ptr != END_OF_LIST(&obj_used_list)) {
3754 if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3755 inst = ptr->instance;
3756 if (!stricmp(goals[i].ship_name, Ships[inst].ship_name)) {
3762 ptr = GET_NEXT(ptr);
3766 return "*Invalid target ship name";
3768 if (wing >= 0) { // check if target ship is in wing
3769 if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3770 return "Target ship of wing's goal is within said wing";
3773 team2 = Ships[inst].team;
3775 } else if (flag == 3) { // target wing required
3776 for (j=0; j<MAX_WINGS; j++)
3777 if (Wings[j].wave_count && !stricmp(Wings[j].name, goals[i].ship_name))
3781 return "*Invalid target wing name";
3783 if (ship >= 0) { // check if ship is in target wing
3784 if (Ships[ship].wingnum == j)
3785 return "Target wing of ship's goal is same wing said ship is part of";
3788 team2 = Ships[Objects[wing_objects[j][0]].instance].team;
3790 } else if (flag == 4) {
3791 ptr = GET_FIRST(&obj_used_list);
3792 while (ptr != END_OF_LIST(&obj_used_list)) {
3793 if (ptr->type == OBJ_SHIP || ptr->type == OBJ_START) {
3794 inst = ptr->instance;
3795 if (!stricmp(goals[i].ship_name, Ships[inst].ship_name)) {
3800 } else if (ptr->type == OBJ_WAYPOINT) {
3801 if (!stricmp(goals[i].ship_name, object_name(OBJ_INDEX(ptr)))) {
3807 ptr = GET_NEXT(ptr);
3811 return "*Invalid target ship or waypoint name";
3814 if (wing >= 0) { // check if target ship is in wing
3815 if (Ships[inst].wingnum == wing && Objects[Ships[inst].objnum].type != OBJ_START)
3816 return "Target ship of wing's goal is within said wing";
3819 team2 = Ships[inst].team;
3823 switch (goals[i].ai_mode) {
3824 case AI_GOAL_DESTROY_SUBSYSTEM:
3825 Assert(flag == 2 && inst >= 0);
3826 if (ship_get_subsys_index(&Ships[inst], goals[i].docker.name, 1) < 0)
3827 return "Unknown subsystem type";
3831 case AI_GOAL_DOCK: {
3832 int dock1 = -1, dock2 = -1, model1, model2;
3834 Assert(flag == 2 && inst >= 0);
3835 if (!ship_docking_valid(ship, inst))
3836 return "Docking illegal between given ship types";
3838 model1 = Ships[ship].modelnum;
3839 num = get_docking_list(model1);
3840 for (j=0; j<num; j++) {
3841 Assert(Docking_bay_list[j]);
3842 if (!stricmp(goals[i].docker.name, Docking_bay_list[j])) {
3848 model2 = Ships[inst].modelnum;
3849 num = get_docking_list(model2);
3850 for (j=0; j<num; j++) {
3851 Assert(Docking_bay_list[j]);
3852 if (!stricmp(goals[i].dockee.name, Docking_bay_list[j])) {
3859 return "Invalid docker point";
3862 return "Invalid dockee point";
3864 if ((dock1 >= 0) && (dock2 >= 0)) {
3865 if ( !(model_get_dock_index_type(model1, dock1) & model_get_dock_index_type(model2, dock2)) )
3866 return "Dock points are incompatible";
3873 switch (goals[i].ai_mode) {
3875 case AI_GOAL_GUARD_WING:
3876 // if ((team == TEAM_HOSTILE && team2 == TEAM_FRIENDLY) || (team == TEAM_FRIENDLY && team2 == TEAM_HOSTILE)) {
3877 if (team != team2) { // MK, added support for TEAM_NEUTRAL. Won't this work?
3879 return "Ship assigned to guard opposite team";
3881 return "Wing assigned to guard opposite team";
3887 case AI_GOAL_CHASE_WING:
3888 case AI_GOAL_DESTROY_SUBSYSTEM:
3889 case AI_GOAL_DISARM_SHIP:
3890 case AI_GOAL_DISABLE_SHIP:
3891 if (team == team2) {
3893 return "Ship assigned to attack same team";
3895 return "Wings assigned to attack same team";
3905 // function (which is called externally from message editor and event editor) so skip through
3906 // the sexpression nodes to look for send-message commands to try to associate message personas
3908 void fred_check_message_personas()
3911 int i, op, j, ship_index;
3912 char *mname, *who_from;
3915 // this function is responsible for assigning personas to ships as well as error checking them.
3916 // clear out the persona index on all ship objects
3917 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3918 if ( objp->type == OBJ_SHIP ) {
3919 Ships[objp->instance].persona_index = -1;
3924 for (i = 0; i < MAX_SEXP_NODES; i++ ) {
3925 if ( Sexp_nodes[i].type == SEXP_NOT_USED )
3928 // look for only operator nodes
3929 if ( Sexp_nodes[i].subtype != SEXP_ATOM_OPERATOR )
3932 // now look for the send-message opeator
3933 op = find_operator( Sexp_nodes[i].text );
3934 if ( op != OP_SEND_MESSAGE )
3937 // have the message. parse through the message to determine who is sending the message.
3938 who_from = CTEXT(CDR(i));
3940 // we can ignore messages from any wingman, and allied, or from God.
3941 if ( !stricmp(who_from, "<Any wingman>") || !stricmp(who_from, "<Any allied>") || (who_from[0] == '#') )
3944 mname = CTEXT(CDR(CDR(CDR(i))));
3946 // check to see if who_from is a wing. Don't do processing if so.
3947 if ( wing_name_lookup(who_from, 1) != -1 )
3950 ship_index = ship_name_lookup( who_from );
3951 if ( ship_index == -1 ) {
3952 Int3(); // get allender. something funny is up with shipnames in send-message
3956 for ( j = Num_builtin_messages; j < Num_messages; j++ ) {
3957 if ( !stricmp(mname, Messages[j].name) ) {
3959 // check to see if there is a persona for this message -- if not, bail
3960 if ( Messages[j].persona_index == -1 )
3963 // if a ship isn't assigned a persona, and this message says that he is, assign it, and move on
3964 if ( Ships[ship_index].persona_index == -1 ) {
3965 Ships[ship_index].persona_index = Messages[j].persona_index;
3969 // we must be sure of the following conditions:
3970 // 1) a ship isn't assigned > 1 persona
3972 if ( Ships[ship_index].persona_index != Messages[j].persona_index )
3973 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 );
3978 // check that two or more ships are not using the same persona
3979 for (i = 0; i < Num_personas; i++ ) {
3983 // move through object list looking for number of shis using this persona
3985 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3986 if ( objp->type != OBJ_SHIP )
3988 if (Ships[objp->instance].persona_index == i )
3992 if ( persona_count > 1 )
3993 Fred_view_wnd->error("Persona %s used by more than 1 ship", Personas[Messages[j].persona_index].name );
3999 void CFREDView::OnViewOutlines()
4001 Show_outlines = !Show_outlines;
4002 theApp.write_ini_file();
4006 void CFREDView::OnUpdateViewOutlines(CCmdUI* pCmdUI)
4008 pCmdUI->SetCheck(Show_outlines);
4011 void CFREDView::OnUpdateNewShipType(CCmdUI* pCmdUI)
4016 z = m_new_ship_type_combo_box.GetCurSelNEW();
4018 m_new_ship_type_combo_box.SetCurSelNEW(cur_model_index);
4020 cur_model_index = z;
4022 bar = GetDlgItem(pCmdUI->m_nID);
4024 pCmdUI -> ContinueRouting();
4025 return; // not for us
4028 pCmdUI -> SetCheck((bar->GetStyle() & WS_VISIBLE) != 0);
4031 void CFREDView::OnShowStarfield()
4033 Show_stars = !Show_stars;
4034 theApp.write_ini_file();
4038 void CFREDView::OnUpdateShowStarfield(CCmdUI* pCmdUI)
4040 pCmdUI->SetCheck(Show_stars);
4043 void CFREDView::OnAsteroidEditor()
4045 asteroid_editor dlg;
4050 void CFREDView::OnRunFreespace()
4054 PROCESS_INFORMATION pi;
4057 if (!FREDDoc_ptr->SaveModified())
4061 si.lpReserved = NULL;
4062 si.lpDesktop = NULL;
4066 si.lpReserved2 = NULL;
4068 r = CreateProcess("..\\..\\Fs.exe", NULL, NULL, NULL, FALSE, 0, NULL, "..\\..", &si, &pi);
4071 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
4074 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
4080 // Display the string.
4081 MessageBox(lpMsgBuf);
4084 LocalFree( lpMsgBuf );
4088 void CFREDView::OnEditorCampaign()
4090 if (!FREDDoc_ptr->SaveModified())
4093 Assert(!Campaign_wnd);
4094 Campaign_wnd = new campaign_tree_wnd;
4095 if (Campaign_wnd->Create(NULL, "Campaign Editor", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
4096 CFrameWnd::rectDefault, NULL, "IDR_MENU_CAMPAIGN")) {
4097 Campaign_wnd->ShowWindow(SW_SHOW);
4098 Campaign_wnd->UpdateWindow();
4102 void CFREDView::OnShowShips()
4104 Show_ships = !Show_ships;
4109 void CFREDView::OnUpdateShowShips(CCmdUI* pCmdUI)
4111 pCmdUI->SetCheck(Show_ships);
4114 void CFREDView::OnShowStarts()
4116 Show_starts = !Show_starts;
4121 void CFREDView::OnUpdateShowStarts(CCmdUI* pCmdUI)
4123 pCmdUI->SetCheck(Show_starts);
4126 void CFREDView::OnShowFriendly()
4128 Show_friendly = !Show_friendly;
4133 void CFREDView::OnUpdateShowFriendly(CCmdUI* pCmdUI)
4135 pCmdUI->SetCheck(Show_friendly);
4138 void CFREDView::OnShowHostile()
4140 Show_hostile = !Show_hostile;
4145 void CFREDView::OnUpdateShowHostile(CCmdUI* pCmdUI)
4147 pCmdUI->SetCheck(Show_hostile);
4150 void CFREDView::OnToggleViewpoint()
4152 if (viewpoint || !query_valid_object())
4157 view_obj = cur_object_index;
4163 void CFREDView::OnRevert()
4165 if (!FREDDoc_ptr->SaveModified())
4168 FREDDoc_ptr->DeleteContents();
4169 FREDDoc_ptr->OnOpenDocument(NULL);
4172 void CFREDView::OnUpdateRevert(CCmdUI* pCmdUI)
4174 pCmdUI->Enable(*Mission_filename);
4177 BOOL CFREDView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
4179 if ((Cursor_over >= 0) || Selection_lock) {
4180 if (Editing_mode == 1) {
4181 SetCursor(h_cursor_move);
4184 } else if (Editing_mode == 2) {
4185 SetCursor(h_cursor_rotate);
4190 return CView::OnSetCursor(pWnd, nHitTest, message);
4193 void CFREDView::OnHideObjects()
4197 ptr = GET_FIRST(&obj_used_list);
4198 while (ptr != END_OF_LIST(&obj_used_list)) {
4199 if (ptr->flags & OF_MARKED) {
4200 ptr->flags |= OF_HIDDEN;
4201 unmark_object(OBJ_INDEX(ptr));
4204 ptr = GET_NEXT(ptr);
4208 void CFREDView::OnShowHiddenObjects()
4212 ptr = GET_FIRST(&obj_used_list);
4213 while (ptr != END_OF_LIST(&obj_used_list)) {
4214 ptr->flags &= ~OF_HIDDEN;
4215 ptr = GET_NEXT(ptr);
4221 void CFREDView::OnEditUndo()
4224 matrix viewer_orient;
4226 if (Undo_available) {
4227 viewer_pos = view_pos;
4228 viewer_orient = view_orient;
4229 FREDDoc_ptr->autoload();
4230 view_pos = viewer_pos;
4231 view_orient = viewer_orient;
4235 void CFREDView::OnUpdateEditUndo(CCmdUI* pCmdUI)
4237 pCmdUI->Enable(Undo_available);
4240 void CFREDView::OnEditorsBriefing()
4242 if (!Briefing_dialog) {
4243 Briefing_dialog = new briefing_editor_dlg;
4244 Briefing_dialog->create();
4247 Briefing_dialog->SetWindowPos(&wndTop, 0, 0, 0, 0,
4248 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
4249 Briefing_dialog->ShowWindow(SW_RESTORE);
4252 void CFREDView::OnEditorsDebriefing()
4254 debriefing_editor_dlg dlg;
4259 void CFREDView::OnSaveCamera()
4261 saved_cam_pos = view_pos;
4262 saved_cam_orient = view_orient;
4265 void CFREDView::OnRestoreCamera()
4267 view_pos = saved_cam_pos;
4268 view_orient = saved_cam_orient;
4272 void CFREDView::OnUpdateRestoreCamera(CCmdUI* pCmdUI)
4274 pCmdUI->Enable(!IS_VEC_NULL(&saved_cam_orient.fvec));
4277 void CFREDView::OnShowSexpHelp()
4281 Show_sexp_help = !Show_sexp_help;
4282 Ship_editor_dialog.show_hide_sexp_help();
4283 Wing_editor_dialog.show_hide_sexp_help();
4285 if (Event_editor_dlg) {
4286 Event_editor_dlg->GetWindowRect(rect);
4288 rect.bottom += SEXP_HELP_BOX_SIZE;
4290 rect.bottom -= SEXP_HELP_BOX_SIZE;
4292 Event_editor_dlg->MoveWindow(rect);
4296 void CFREDView::OnUpdateShowSexpHelp(CCmdUI* pCmdUI)
4298 pCmdUI->SetCheck(Show_sexp_help);
4301 void CFREDView::OnLookatObj()
4303 Lookat_mode = !Lookat_mode;
4304 if (Lookat_mode && query_valid_object()) {
4308 loc = Objects[cur_object_index].pos;
4309 vm_vec_sub(&v, &loc, &view_pos);
4311 if (v.x || v.y || v.z) {
4312 vm_vector_2_matrix(&m, &v, NULL, NULL);
4318 void CFREDView::OnUpdateLookatObj(CCmdUI* pCmdUI)
4320 pCmdUI->SetCheck(Lookat_mode);
4323 void CFREDView::OnGroup(UINT nID)
4325 int n = 1 << (nID - ID_GROUP1);
4329 objp = GET_FIRST(&obj_used_list);
4330 while (objp != END_OF_LIST(&obj_used_list)) {
4331 if (objp->type == OBJ_SHIP) {
4332 if (Ships[objp->instance].group & n)
4333 mark_object(OBJ_INDEX(objp));
4336 objp = GET_NEXT(objp);
4342 void CFREDView::OnSetGroup(UINT nID)
4344 int i, err = 0, n = 1 << (nID - ID_SET_GROUP1);
4347 for (i=0; i<MAX_SHIPS; i++)
4348 Ships[i].group &= ~n;
4350 objp = GET_FIRST(&obj_used_list);
4351 while (objp != END_OF_LIST(&obj_used_list)) {
4352 if (objp->flags & OF_MARKED) {
4353 if (objp->type == OBJ_SHIP) {
4354 Ships[objp->instance].group |= n;
4360 objp = GET_NEXT(objp);
4364 Fred_main_wnd->MessageBox("Only ships can be in groups, and not players or waypoints, etc.\n"
4365 "These illegal objects you marked were not placed in the group");
4370 void CFREDView::OnInitialUpdate()
4372 char *ptr, text[512];
4374 CView::OnInitialUpdate();
4376 // check the time/checksum strings.
4379 if ( memcmp(ptr, DEFAULT_CHECKSUM_STRING, strlen(DEFAULT_CHECKSUM_STRING)) ) {
4380 int stamped_checksum, checksum;
4382 // the checksum is not the default checksum. Calculate the checksum of the string
4384 memcpy(&stamped_checksum, ptr, sizeof(stamped_checksum) );
4386 ptr += 8; // get us to the actual string to calculate the checksum
4387 CALCULATE_STAMP_CHECKSUM();
4389 if ( checksum != stamped_checksum ){
4390 expire_game = EXPIRE_BAD_CHECKSUM;
4393 // now check the time
4396 if ( memcmp( ptr, DEFAULT_TIME_STRING, strlen(DEFAULT_TIME_STRING)) ) {
4397 int expire_time, current_time;
4399 // not the default time -- check against the current time
4400 memcpy( &expire_time, ptr, sizeof(expire_time) );
4401 time( (long *)¤t_time );
4402 if ( current_time > expire_time )
4403 expire_game = EXPIRE_BAD_TIME;
4406 // since the default checksum has changed -- put up a message which shows who the program
4410 sprintf(text, "This version of Fred has been compiled for %s", ptr);
4411 MessageBox(text, NULL, MB_OK);
4414 SetTimer(1, FRED_EXPIRE_TIME, expire_game_proc);
4418 void CFREDView::OnEditorsAdjustGrid()
4420 adjust_grid_dlg dlg;
4426 void CFREDView::OnEditorsShieldSys()
4433 void CFREDView::OnLevelObj()
4439 void CFREDView::OnAlignObj()
4441 verticalize_controlled();
4445 void CFREDView::OnControlObj()
4447 Control_mode = (Control_mode + 1) % 2;
4450 void CFREDView::OnNextObj()
4454 if (Bg_bitmap_dialog) {
4455 if (Cur_bitmap == -1)
4457 if (Num_starfield_bitmaps)
4460 Bg_bitmap_dialog -> update_data();
4467 if (Cur_bitmap >= Num_starfield_bitmaps)
4470 Bg_bitmap_dialog -> update_data();
4474 if (EMPTY(&obj_used_list))
4477 if (query_valid_object()) {
4478 ptr = Objects[cur_object_index].next;
4479 if (ptr == END_OF_LIST(&obj_used_list))
4480 ptr = GET_NEXT(ptr);
4483 ptr = GET_FIRST(&obj_used_list);
4485 if (Marked > 1) { // cycle through marked list
4486 while (!(ptr->flags & OF_MARKED))
4488 ptr = GET_NEXT(ptr);
4489 if (ptr == END_OF_LIST(&obj_used_list))
4490 ptr = GET_NEXT(ptr);
4493 set_cur_object_index(OBJ_INDEX(ptr));
4497 unmark_object(cur_object_index);
4499 mark_object(OBJ_INDEX(ptr));
4503 void CFREDView::OnPrevObj()
4505 int arr[MAX_OBJECTS], i = 0, n = 0;
4508 if (Bg_bitmap_dialog) {
4509 if (Cur_bitmap == -1)
4511 if (Num_starfield_bitmaps)
4513 Cur_bitmap = Num_starfield_bitmaps - 1;
4514 Bg_bitmap_dialog -> update_data();
4522 Cur_bitmap = Num_starfield_bitmaps - 1;
4524 Bg_bitmap_dialog -> update_data();
4528 if (EMPTY(&obj_used_list))
4531 ptr = GET_FIRST(&obj_used_list);
4532 while (ptr != END_OF_LIST(&obj_used_list)) {
4533 if (cur_object_index == OBJ_INDEX(ptr))
4536 arr[n++] = OBJ_INDEX(ptr);
4537 ptr = GET_NEXT(ptr);
4541 if (query_valid_object()) {
4549 if (Marked > 1) { // cycle through marked list
4550 while (!(Objects[i].flags & OF_MARKED))
4557 set_cur_object_index(i);
4561 unmark_object(cur_object_index);
4567 void CFREDView::OnEditDelete()
4569 if (!button_down && Marked) {
4571 FREDDoc_ptr->autosave("object delete");
4574 Update_window = 2; // For some strange reason, need to redraw twice for it to take.
4577 void CFREDView::OnEditDeleteWing()
4579 if (!button_down && (cur_wing >= 0)) {
4581 FREDDoc_ptr->autosave("wing delete");
4584 Ship_editor_dialog.initialize_data(1);
4586 Wing_editor_dialog.initialize_data(1);
4589 Update_window = 2; // For some strange reason, need to redraw twice for it to take.
4592 void CFREDView::OnMarkWing()
4594 int i, wing = cur_wing;
4599 for (i=0; i<Wings[wing].wave_count; i++)
4600 mark_object(wing_objects[wing][i]);
4602 Assert(Wings[wing].special_ship >= 0 && Wings[wing].special_ship < Wings[wing].wave_count);
4603 set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]);
4607 void CFREDView::OnUpdateControlObj(CCmdUI* pCmdUI)
4609 pCmdUI->SetCheck(Control_mode != 0);
4612 void CFREDView::OnAaGridlines()
4614 Aa_gridlines = !Aa_gridlines;
4617 void CFREDView::OnUpdateAaGridlines(CCmdUI* pCmdUI)
4619 pCmdUI->SetCheck(Aa_gridlines);
4623 void CFREDView::OnCmdBrief()
4631 void CFREDView::OnDisableUndo()
4633 Autosave_disabled = !Autosave_disabled;
4636 void CFREDView::OnUpdateDisableUndo(CCmdUI* pCmdUI)
4638 pCmdUI->SetCheck(Autosave_disabled);
4641 void CFREDView::OnUpdateCmdBrief(CCmdUI* pCmdUI)
4643 pCmdUI->Enable(!(The_mission.game_type & MISSION_TYPE_MULTI));
4646 int get_visible_sub_system_count(ship *shipp)
4649 ship_subsys *cur_subsys;
4651 for (cur_subsys = GET_FIRST(&shipp->subsys_list); cur_subsys != END_OF_LIST(&shipp->subsys_list); cur_subsys = GET_NEXT(cur_subsys)) {
4652 if (cur_subsys->system_info->subobj_num != -1) {
4660 int get_next_visible_subsys(ship *shipp, ship_subsys **next_subsys)
4662 int count = get_visible_sub_system_count(shipp);
4664 // return don't try to display
4670 if (*next_subsys == NULL) {
4671 *next_subsys = &shipp->subsys_list;
4675 for (*next_subsys = GET_NEXT(*next_subsys); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4676 if ((*next_subsys)->system_info->subobj_num != -1) {
4682 // look for first after wrap
4683 for (*next_subsys = GET_FIRST(&shipp->subsys_list); *next_subsys != END_OF_LIST(&shipp->subsys_list); *next_subsys = GET_NEXT(*next_subsys)) {
4684 if ((*next_subsys)->system_info->subobj_num != -1) {
4690 Int3(); // should be impossible to miss
4694 int get_prev_visible_subsys(ship *shipp, ship_subsys **prev_subsys)
4696 int count = get_visible_sub_system_count(shipp);
4698 // return don't try to display
4704 Assert(*prev_subsys != NULL);
4707 for (*prev_subsys = GET_PREV(*prev_subsys); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4708 if ((*prev_subsys)->system_info->subobj_num != -1) {
4714 // look for first after wrap
4715 for (*prev_subsys = GET_LAST(&shipp->subsys_list); *prev_subsys != END_OF_LIST(&shipp->subsys_list); *prev_subsys = GET_PREV(*prev_subsys)) {
4716 if ((*prev_subsys)->system_info->subobj_num != -1) {
4722 Int3(); // should be impossible to miss
4726 // update next subsystem to view
4727 void CFREDView::OnNextSubsys()
4731 if (cur_object_index < 0) {
4735 objp = &Objects[cur_object_index];
4737 // check if cur object is ship type
4738 if (objp->type == OBJ_SHIP) {
4740 // check if same ship
4741 if (Render_subsys.ship_obj == objp) {
4743 // if already on, advance to next
4744 if (Render_subsys.do_render) {
4745 if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4755 // set up new and advance to first
4756 Render_subsys.do_render = true;
4757 Render_subsys.ship_obj = objp;
4758 if ( !get_next_visible_subsys(&Ships[objp->instance], &Render_subsys.cur_subsys) ) {
4768 void CFREDView::OnPrevSubsys()
4770 if (!Render_subsys.do_render) {
4774 if ( (cur_object_index < 0) || (Objects[cur_object_index].type != OBJ_SHIP) || (&Objects[cur_object_index] != Render_subsys.ship_obj) ) {
4779 if ( !get_prev_visible_subsys(&Ships[Objects[cur_object_index].instance], &Render_subsys.cur_subsys) ) {
4785 void CFREDView::OnCancelSubsys()
4787 Render_subsys.do_render = false;
4788 Render_subsys.ship_obj = NULL;
4789 Render_subsys.cur_subsys = NULL;
4793 void CFREDView::OnShowPaths()
4795 Show_paths_fred = !Show_paths_fred;
4796 theApp.write_ini_file();
4800 void CFREDView::OnUpdateShowPaths(CCmdUI* pCmdUI)
4802 pCmdUI->SetCheck(Show_paths_fred);
4805 void CFREDView::OnShowDockPoints()
4807 Show_dock_points = !Show_dock_points;
4808 theApp.write_ini_file();
4812 void CFREDView::OnUpdateShowDockPoints(CCmdUI* pCmdUI)
4814 pCmdUI->SetCheck(Show_dock_points);
4817 void CFREDView::OnDumpStats()