FS2_Open
Open source remastering of the Freespace 2 engine
wing.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "stdafx.h"
13 #include "FRED.h"
14 #include "FREDDoc.h"
15 #include "FREDView.h"
16 #include "render/3d.h"
17 #include "physics/physics.h"
18 #include "object/object.h"
19 #include "editor.h"
20 #include "ship/ship.h"
21 #include "math/vecmat.h"
22 #include "Management.h"
23 #include "globalincs/linklist.h"
24 #include "MainFrm.h"
25 #include "wing.h"
26 #include "CreateWingDlg.h"
27 #include "Management.h"
28 
29 #define MULTI_WING 999999
30 
31 #ifdef _DEBUG
32 #undef THIS_FILE
33 static char THIS_FILE[] = __FILE__;
34 #endif
35 
37 
38 void remove_player_from_wing(int player, int min = 1);
39 
40 // Finds a free wing slot (i.e. unused)
42 {
43  int i;
44 
45  for (i=0; i<MAX_WINGS; i++)
46  if (!Wings[i].wave_count)
47  return i;
48 
49  return -1;
50 }
51 
52 int check_wing_dependencies(int wing_num)
53 {
54  char *name;
55 
56  name = Wings[wing_num].name;
57  return reference_handler(name, REF_TYPE_WING, -1);
58 }
59 
60 void mark_wing(int wing)
61 {
62  int i;
63 
64  unmark_all();
65  Assert(Wings[wing].special_ship >= 0 && Wings[wing].special_ship < Wings[wing].wave_count);
66  set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]);
67  for (i=0; i<Wings[wing].wave_count; i++)
68  mark_object(wing_objects[wing][i]);
69 }
70 
71 // delete a whole wing, also deleting its ships if necessary.
72 int delete_wing(int wing_num, int bypass)
73 {
74  int i, r, total;
75 
77  return 0;
78 
79  r = check_wing_dependencies(wing_num);
80  if (r)
81  return r;
82 
84  for (i=0; i<Num_reinforcements; i++)
85  if (!stricmp(Wings[wing_num].name, Reinforcements[i].name)) {
87  break;
88  }
89 
90  invalidate_references(Wings[wing_num].name, REF_TYPE_WING);
91  if (!bypass) {
92  total = Wings[wing_num].wave_count;
93  for (i=0; i<total; i++)
94  delete_object(wing_objects[wing_num][i]);
95  }
96 
97  Wings[wing_num].wave_count = 0;
98  Wings[wing_num].wing_squad_filename[0] = '\0';
99  Wings[wing_num].wing_insignia_texture = -1;
100 
101  if (cur_wing == wing_num)
102  set_cur_wing(cur_wing = -1); // yes, one '=' is correct.
103 
104  free_sexp2(Wings[wing_num].arrival_cue);
105  free_sexp2(Wings[wing_num].departure_cue);
106 
107  Num_wings--;
108  set_modified();
109 
111 
113  return 0;
114 }
115 
116 // delete a whole wing, leaving ships intact but wingless.
117 void remove_wing(int wing_num)
118 {
119  int i, total;
120  object *ptr;
121 
122  if (check_wing_dependencies(wing_num))
123  return;
124 
127  total = Wings[wing_num].wave_count;
128  for (i=0; i<total; i++) {
129  ptr = &Objects[wing_objects[wing_num][i]];
130  if (ptr->type == OBJ_SHIP)
132  else if (ptr->type == OBJ_START)
134  }
135 
136  Assert(!Wings[wing_num].wave_count);
137 
138  Wings[wing_num].wave_count = 0;
139  Wings[wing_num].wing_squad_filename[0] = '\0';
140  Wings[wing_num].wing_insignia_texture = -1;
141 
144 
145  if (cur_wing == wing_num) {
146  set_cur_wing(cur_wing = -1); // yes, one '=' is correct.
147  }
148 
149  free_sexp2(Wings[wing_num].arrival_cue);
150  free_sexp2(Wings[wing_num].departure_cue);
151 
152  Num_wings--;
153 
155 
156  set_modified();
157 }
158 
159 // Takes a ship out of a wing, deleting wing if that was the only ship in it.
160 void remove_ship_from_wing(int ship, int min)
161 {
162  char buf[256];
163  int i, wing, end, obj;
164 
165  wing = Ships[ship].wingnum;
166  if (wing != -1) {
167  if (Wings[wing].wave_count == min)
168  {
169  Wings[wing].wave_count = 0;
170  Wings[wing].wing_squad_filename[0] = '\0';
172  delete_wing(wing);
173  }
174  else
175  {
176  i = Wings[wing].wave_count;
177  end = i - 1;
178  while (i--)
179  if (wing_objects[wing][i] == Ships[ship].objnum)
180  break;
181 
182  Assert(i != -1); // Error, object should be in wing.
183  if (Wings[wing].special_ship == i)
184  Wings[wing].special_ship = 0;
185 
186  // if not last element, move last element to position to fill gap
187  if (i != end) {
188  obj = wing_objects[wing][i] = wing_objects[wing][end];
190  if (Objects[obj].type == OBJ_SHIP) {
191  wing_bash_ship_name(buf, Wings[wing].name, i + 1);
192  rename_ship(Wings[wing].ship_index[i], buf);
193  }
194  }
195 
196  Wings[wing].wave_count--;
197  if (Wings[wing].wave_count && (Wings[wing].threshold >= Wings[wing].wave_count))
199  }
200 
201  Ships[ship].wingnum = -1;
202  }
203 
204  set_modified();
205  // reset ship name to non-wing default ship name
206  sprintf(buf, "%s %d", Ship_info[Ships[ship].ship_info_index].name, ship);
207  rename_ship(ship, buf);
208 }
209 
210 // Takes a player out of a wing, deleting wing if that was the only ship in it.
211 void remove_player_from_wing(int player, int min)
212 {
213  remove_ship_from_wing(player, min);
214 }
215 
216 // Forms a wing from marked objects
218 {
219  char msg[1024];
220  int i, ship, wing = -1, waypoints = 0, count = 0, illegal_ships = 0;
221  int leader, leader_team;
222  object *ptr;
223  create_wing_dlg dlg;
224 
225  if (!query_valid_object())
226  return -1;
227 
228  leader = cur_object_index;
229  ptr = GET_FIRST(&obj_used_list);
230  while (ptr != END_OF_LIST(&obj_used_list)) {
231  if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags & OF_MARKED)) {
232  count++;
233  i = -1;
234  switch (ptr->type) {
235  case OBJ_SHIP:
236  case OBJ_START:
237  i = Ships[ptr->instance].wingnum;
238  break;
239  }
240 
241  if (i >= 0) {
242  if (wing < 0)
243  wing = i;
244  else if (wing != i)
245  wing = MULTI_WING;
246  }
247  }
248 
249  ptr = GET_NEXT(ptr);
250  }
251 
252  if (count > MAX_SHIPS_PER_WING) {
253  sprintf(msg, "You have too many ships marked!\n"
254  "A wing is limited to %d ships total", MAX_SHIPS_PER_WING);
255 
256  Fred_main_wnd->MessageBox(msg, "Error", MB_ICONEXCLAMATION);
257  return -1;
258  }
259 
260  if ((wing >= 0) && (wing != MULTI_WING)) {
261  sprintf(msg, "Do you want to reform wing \"%s\"?", Wings[wing].name);
262  i = Fred_main_wnd->MessageBox(msg, "Query", MB_YESNOCANCEL);
263  if (i == IDCANCEL)
264  return -1;
265 
266  else if (i == IDNO)
267  wing = -1;
268 
269  else { // must be IDYES
270  for (i=Wings[wing].wave_count-1; i>=0; i--) {
271  ptr = &Objects[wing_objects[wing][i]];
272  switch (ptr->type) {
273  case OBJ_SHIP:
275  break;
276 
277  case OBJ_START:
279  break;
280 
281  default:
282  Int3(); // shouldn't be in a wing!
283  }
284  }
285 
286  Assert(!Wings[wing].wave_count);
287  Num_wings--;
288  }
289 
290  } else
291  wing = -1;
292 
293  if (wing < 0) {
294  wing = find_free_wing();
295 
296  if (wing < 0) {
297  Fred_main_wnd->MessageBox("Too many wings, can't create more!",
298  "Error", MB_ICONEXCLAMATION);
299 
300  return -1;
301  }
302 
303  Wings[wing].num_waves = 1;
304  Wings[wing].threshold = 0;
307  Wings[wing].arrival_anchor = -1;
308  Wings[wing].arrival_delay = 0;
312  Wings[wing].hotkey = -1;
313  Wings[wing].flags = 0;
316 
317  for (i=0; i<MAX_AI_GOALS; i++) {
319  Wings[wing].ai_goals[i].priority = -1; // this sets up the priority field to be like ships
320  }
321 
322  if (dlg.DoModal() == IDCANCEL)
323  return -1;
324 
325  dlg.m_name.TrimLeft();
326  dlg.m_name.TrimRight();
327  string_copy(Wings[wing].name, dlg.m_name, NAME_LENGTH - 1);
328  }
329 
330  set_cur_indices(-1);
331  ptr = GET_FIRST(&obj_used_list);
332  while (ptr != END_OF_LIST(&obj_used_list)) {
333  if (ptr->flags & OF_MARKED) {
334 // if ((ptr->type == OBJ_START) && (ptr->instance)) {
335 // starts++;
336 // unmark_object(OBJ_INDEX(ptr));
337 
338 // } else if (ptr->type == OBJ_WAYPOINT) {
339  if (ptr->type == OBJ_WAYPOINT) {
340  waypoints++;
341  unmark_object(OBJ_INDEX(ptr));
342 
343  } else if (ptr->type == OBJ_SHIP) {
344  int ship_type = ship_query_general_type(ptr->instance);
345  if(ship_type < 0 || !(Ship_types[ship_type].ai_bools & STI_AI_CAN_FORM_WING))
346  {
347  illegal_ships++;
348  unmark_object(OBJ_INDEX(ptr));
349  }
350  }
351  }
352 
353  ptr = GET_NEXT(ptr);
354  }
355 
356  // if this wing is a player starting wing, automatically set the hotkey for this wing
357  for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
358  if ( !stricmp(Wings[wing].name, Starting_wing_names[i]) ) {
359  Wings[wing].hotkey = i;
360  break;
361  }
362  }
363 
364  count = 0;
366  count = 1;
367 
368  ptr = GET_FIRST(&obj_used_list);
369  while (ptr != END_OF_LIST(&obj_used_list)) {
370  if (ptr->flags & OF_MARKED) {
371  if ((ptr->type == OBJ_START) && (ptr->instance == Player_start_shipnum))
372  i = 0; // player 1 start always goes to front of the wing
373  else
374  i = count++;
375 
376  Assert((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START));
377  ship = ptr->instance;
378  if (Ships[ship].wingnum != -1) {
379  if (ptr->type == OBJ_SHIP)
380  remove_ship_from_wing(ship);
381  else
383  }
384 
385  wing_bash_ship_name(msg, Wings[wing].name, i + 1);
386  rename_ship(ship, msg);
387 
388  Wings[wing].ship_index[i] = ship;
389  Ships[ship].wingnum = wing;
390  if (Ships[ship].arrival_cue >= 0)
391  free_sexp2(Ships[ship].arrival_cue);
392 
394  if (Ships[ship].departure_cue >= 0)
395  free_sexp2(Ships[ship].departure_cue);
396 
398 
399  wing_objects[wing][i] = OBJ_INDEX(ptr);
400  if (OBJ_INDEX(ptr) == leader)
402  }
403 
404  ptr = GET_NEXT(ptr);
405  }
406 
407  if (!count) // this should never happen, so if it does, needs to be fixed now.
408  Error(LOCATION, "No valid ships were selected to form wing from");
409 
411  Num_wings++;
412 
413 // if (starts)
414 // Fred_main_wnd->MessageBox("Multi-player starting points can't be part of a wing!\n"
415 // "All marked multi-player starting points were ignored",
416 // "Error", MB_ICONEXCLAMATION);
417 
418  if (waypoints)
419  Fred_main_wnd->MessageBox("Waypoints can't be part of a wing!\n"
420  "All marked waypoints were ignored",
421  "Error", MB_ICONEXCLAMATION);
422 
423  if (illegal_ships)
424  Fred_main_wnd->MessageBox("Some ship types aren't allowed to be in a wing.\n"
425  "All marked ships of these types were ignored",
426  "Error", MB_ICONEXCLAMATION);
427 
428 
429  leader_team = Ships[Wings[wing].ship_index[Wings[wing].special_ship]].team;
430  for (i = 0; i < Wings[wing].wave_count; i++)
431  {
432  if (Ships[Wings[wing].ship_index[i]].team != leader_team)
433  {
434  Fred_main_wnd->MessageBox("Wing contains ships on different teams", "Warning");
435  break;
436  }
437  }
438 
439  mark_wing(wing);
440 
442 
443  return 0;
444 }
445 
447 // Old stuff down there..
448 
449 #define MAX_WING_VECTORS 8 // 8 vectors per wing formation. Possible to have more
450  // than 8 ships. A vector is where a ship is located relative
451  // to the leader. Other ships can be located at the same
452  // vector relative to another member. So wing formation
453  // size is not limited by this constant.
454 #define MAX_WING_FORMATIONS 8 // 8 different kinds of wing formations
455 
456 typedef struct formation {
459 } formation;
460 
462 
463 //wing Wings[MAX_WINGS];
464 
466 
468 {
469  if (Wings_initialized)
470  return;
471 
472  Wings_initialized = 1;
473 
474  Wing_formations[0].num_vectors = 2;
475 
476  Wing_formations[0].offsets[0].xyz.x = -5.0f;
477  Wing_formations[0].offsets[0].xyz.y = +1.0f;
478  Wing_formations[0].offsets[0].xyz.z = -5.0f;
479 
480  Wing_formations[0].offsets[1].xyz.x = +5.0f;
481  Wing_formations[0].offsets[1].xyz.y = +1.0f;
482  Wing_formations[0].offsets[1].xyz.z = -5.0f;
483 }
484 
486 {
487  int i;
488 
489  for (i=0; i<MAX_WINGS; i++)
490  Wings[i].wave_count= 0;
491 
492  for (i=0; i<MAX_OBJECTS; i++)
493  if (Objects[i].type != OBJ_NONE)
494  if (get_wingnum(i) != -1) {
495  int wingnum = get_wingnum(i);
496 
497  Assert((wingnum >= 0) && (wingnum < MAX_WINGS));
498  Assert(Wings[wingnum].wave_count < MAX_SHIPS_PER_WING);
499 // JEH strcpy_s(Wings[wingnum].ship_names[Wings[wingnum].count++], i;
500  }
501 
502 }
503 
505 {
506  int i;
507 
508  for (i=1; i<MAX_OBJECTS; i++)
509  if (Objects[i].type == OBJ_NONE)
510  return i;
511 
512  return -1;
513 }
char Starting_wing_names[MAX_STARTING_WINGS][NAME_LENGTH]
Definition: ship.cpp:139
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
void wing_bash_ship_name(char *ship_name, const char *wing_name, int index)
Definition: ship.cpp:12686
int i
Definition: multi_pxo.cpp:466
int wave_delay_min
Definition: ship.h:1552
int Locked_sexp_false
Definition: sexp.cpp:828
int team
Definition: ship.h:606
int arrival_anchor
Definition: ship.h:1541
int wave_delay_max
Definition: ship.h:1553
int arrival_distance
Definition: ship.h:1540
int Player_start_shipnum
int arrival_location
Definition: ship.h:1539
CShipEditorDlg Ship_editor_dialog
Definition: fred.cpp:55
void update_custom_wing_indexes()
#define REF_TYPE_WING
Definition: sexp.h:837
void unmark_all()
#define MAX_WINGS
Definition: globals.h:50
int rename_ship(int ship, char *name)
void remove_wing(int wing_num)
Definition: wing.cpp:117
int delete_object(int obj)
Assert(pm!=NULL)
Definition: pstypes.h:88
void create_wings_from_objects(void)
Definition: wing.cpp:485
char wing_squad_filename[MAX_FILENAME_LEN]
Definition: ship.h:1518
void set_cur_wing(int wing)
struct vec3d::@225::@227 xyz
CButton * team
int update_data(int redraw=1)
void set_cur_indices(int obj)
vec3d offsets[MAX_WING_VECTORS]
Definition: wing.cpp:458
#define MAX_OBJECTS
Definition: globals.h:83
object obj_used_list
Definition: object.cpp:53
int cur_wing
Definition: management.cpp:77
#define MULTI_WING
Definition: wing.cpp:29
int create_wing()
Definition: wing.cpp:217
CMainFrame * Fred_main_wnd
Definition: mainfrm.cpp:89
Definition: ship.h:1516
int wing_insignia_texture
Definition: ship.h:1566
#define MB_YESNOCANCEL
Definition: config.h:183
int Wings_initialized
Definition: wing.cpp:465
#define MAX_SHIPS_PER_WING
Definition: globals.h:52
int invalidate_references(char *name, int type)
#define Int3()
Definition: pstypes.h:292
#define AI_GOAL_NONE
Definition: ai.h:194
int arrival_delay
Definition: ship.h:1544
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
int hotkey
Definition: ship.h:1520
GLenum type
Definition: Gl.h:1492
struct formation formation
reinforcements Reinforcements[MAX_REINFORCEMENTS]
Definition: ship.cpp:165
int query_valid_object(int index)
int check_wing_dependencies(int wing_num)
Definition: wing.cpp:52
int Locked_sexp_true
Definition: sexp.cpp:828
#define OBJ_WAYPOINT
Definition: object.h:36
int instance
Definition: object.h:150
Definition: player.h:85
#define OBJ_START
Definition: object.h:35
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
int num_vectors
Definition: wing.cpp:457
void set_cur_object_index(int obj)
char name[NAME_LENGTH]
Definition: ship.h:1517
int wingnum
Definition: ship.h:623
#define MAX_STARTING_WINGS
Definition: globals.h:54
void remove_ship_from_wing(int ship, int min)
Definition: wing.cpp:160
int departure_cue
Definition: ship.h:1549
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
int ai_mode
Definition: ai.h:136
#define MAX_AI_GOALS
Definition: ai.h:91
void delete_reinforcement(int num)
int free_sexp2(int num)
Definition: sexp.cpp:1321
int priority
Definition: ai.h:141
int Num_wings
Definition: ship.cpp:120
int wing_objects[MAX_WINGS][MAX_SHIPS_PER_WING]
Definition: management.cpp:97
Definition: ship.h:534
formation Wing_formations[MAX_WING_FORMATIONS]
Definition: wing.cpp:461
int wave_count
Definition: ship.h:1527
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
void string_copy(char *dest, const CString &src, int max_len, int modify)
Definition: management.cpp:142
#define OBJ_INDEX(objp)
Definition: object.h:235
#define OF_MARKED
Definition: object.h:125
void remove_player_from_wing(int player, int min=1)
Definition: wing.cpp:211
int get_free_objnum(void)
Definition: wing.cpp:504
int num_waves
Definition: ship.h:1522
int ship_query_general_type(int ship)
Definition: ship.cpp:14475
#define OBJ_SHIP
Definition: object.h:32
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
wing_editor Wing_editor_dialog
Definition: fred.cpp:56
GLbitfield flags
Definition: Glext.h:6722
void set_modified(BOOL arg)
Definition: freddoc.cpp:676
GLuint const GLchar * name
Definition: Glext.h:5608
#define MAX_WING_VECTORS
Definition: wing.cpp:449
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define STI_AI_CAN_FORM_WING
Definition: ship.h:1009
int bypass_errors
Definition: wing_editor.h:22
#define MB_ICONEXCLAMATION
Definition: config.h:184
int arrival_cue
Definition: ship.h:1543
#define NAME_LENGTH
Definition: globals.h:15
int delete_wing(int wing_num, int bypass)
Definition: wing.cpp:72
int find_free_wing()
Definition: wing.cpp:41
int special_ship
Definition: ship.h:1537
void mark_object(int obj)
int departure_location
Definition: ship.h:1546
int departure_delay
Definition: ship.h:1550
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
int already_deleting_wing
Definition: wing.cpp:36
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
int threshold
Definition: ship.h:1523
int get_wingnum(int objnum)
Definition: ai.cpp:57
void unmark_object(int obj)
GLint GLsizei count
Definition: Gl.h:1491
void mark_wing(int wing)
Definition: wing.cpp:60
int Num_reinforcements
Definition: ship.cpp:121
int cur_object_index
Definition: management.cpp:79
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
int departure_cue
Definition: ship.h:620
int reference_handler(char *name, int type, int obj)
void initialize_wings(void)
Definition: wing.cpp:467
#define OBJ_NONE
Definition: object.h:31
int arrival_cue
Definition: ship.h:614
uint flags
Definition: object.h:151
char type
Definition: object.h:146
#define stricmp(s1, s2)
Definition: config.h:271
#define MAX_WING_FORMATIONS
Definition: wing.cpp:454
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
GLuint GLuint end
Definition: Gl.h:1502
struct wing wing
int flags
Definition: ship.h:1556
ai_goal ai_goals[MAX_AI_GOALS]
Definition: ship.h:1558
void initialize_data(int full)