]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/wing.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / fred2 / wing.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Fred2/wing.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Wing management functions for dealing with wing related operations
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:17  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:44  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:09  root
25  * Initial import.
26  *
27  * 
28  * 4     7/09/99 5:54p Dave
29  * Seperated cruiser types into individual types. Added tons of new
30  * briefing icons. Campaign screen.
31  * 
32  * 3     3/01/99 10:00a Dave
33  * Fxied several dogfight related stats bugs.
34  * 
35  * 2     10/07/98 6:28p Dave
36  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
37  * Fred. Globalized mission and campaign file extensions. Removed Silent
38  * Threat specific code.
39  * 
40  * 1     10/07/98 3:02p Dave
41  * 
42  * 1     10/07/98 3:00p Dave
43  * 
44  * 59    2/26/98 4:59p Allender
45  * groundwork for team vs team briefings.  Moved weaponry pool into the
46  * Team_data structure.  Added team field into the p_info structure.
47  * Allow for mutliple structures in the briefing code.
48  * 
49  * 58    1/06/98 2:27p Hoffoss
50  * Made wing deleting free up arrival and departure cue sexp trees, which
51  * wasn't happening before for some reason.
52  * 
53  * 57    12/29/97 4:55p Johnson
54  * Added some fixes.
55  * 
56  * 56    11/21/97 11:46a Johnson
57  * Changed code to delete reinforcement wings when the wing is deleted.
58  * 
59  * 55    11/13/97 4:14p Allender
60  * automatic assignment of hotkeys for starting wings.  Appripriate
61  * warnings when they are incorrectly used.  hotkeys correctly assigned to
62  * ships/wing arriving after mission start
63  * 
64  * 54    10/01/97 12:37p Hoffoss
65  * Changed Fred (and FreeSpace) to utilize alpha, beta and gamma as player
66  * starting wing names.
67  * 
68  * 53    9/16/97 9:41p Hoffoss
69  * Changed Fred code around to stop using Parse_player structure for
70  * player information, and use actual ships instead.
71  * 
72  * 52    9/11/97 4:04p Hoffoss
73  * Fixed bug in Fred: disband wing wasn't making sure the ship editor's
74  * data was synced.
75  * 
76  * 51    9/06/97 2:13p Mike
77  * Replace support for TEAM_NEUTRAL
78  * 
79  * 50    9/02/97 3:44p Johnson
80  * Fixed bugs with thresholds not being lowered.
81  * 
82  * 49    9/02/97 3:24p Johnson
83  * Fixed bug: ships removed from wings will lower threshold if required.
84  * 
85  * 48    8/30/97 9:52p Hoffoss
86  * Implemented arrival location, distance, and anchor in Fred.
87  * 
88  * 47    8/25/97 5:58p Hoffoss
89  * Created menu items for keypress functions in Fred, and fixed bug this
90  * uncovered with wing_delete function.
91  * 
92  * 46    8/16/97 6:44p Hoffoss
93  * Changes to allow any player to be in a wing.
94  * 
95  * 45    8/16/97 4:51p Hoffoss
96  * Fixed bugs with wing deletion and removing ships from a wing.
97  * 
98  * 44    8/15/97 1:07a Hoffoss
99  * Changed code to disallow some ship types from being in a wing, and
100  * disallowing some ship types from being able to have initial orders.
101  * 
102  * 43    8/12/97 1:55a Hoffoss
103  * Made extensive changes to object reference checking and handling for
104  * object deletion call.
105  * 
106  * 42    8/10/97 4:24p Hoffoss
107  * Added warning when creating a wing if wing is mixed.
108  * 
109  * 41    8/08/97 1:31p Hoffoss
110  * Added syncronization protection to cur_object_index changes.
111  * 
112  * 40    8/08/97 10:07a Hoffoss
113  * Fixed bug where ship references aren't updated when wing is created
114  * (i.e. ships being renamed, but not in the references too).
115  * 
116  * 39    8/01/97 3:24p Hoffoss
117  * Fixed bug where when player is removed from a wing, the ship associated
118  * with the player doesn't get it's wingnum variable updated.
119  * 
120  * 38    7/09/97 2:38p Allender
121  * organized ship/wing editor dialogs.  Added protect ship and ignore
122  * count checkboxes to those dialogs.  Changed flag code for
123  * parse_objects.  Added unprotect sexpressions
124  * 
125  * 37    6/30/97 11:36a Hoffoss
126  * Fixed bug with wing reforming.
127  * 
128  * 36    6/18/97 2:36p Hoffoss
129  * Wing ship numbering starts at 1 instead of 0, and changed form wing to
130  * allow reforming a wing.
131  * 
132  * 35    6/04/97 12:00a Allender
133  * make wing goal priorities default to -1 so that their priorities get
134  * set more appropriatly in the initial order dialog
135  * 
136  * 34    5/14/97 4:08p Lawrance
137  * removing my_index from game arrays
138  * 
139  * 33    5/08/97 10:54a Hoffoss
140  * Fixed bug in reforming wings screwing up ship names.
141  * 
142  * 32    4/30/97 9:17a Hoffoss
143  * Hotkey for wing set to none when new wing created.
144  * 
145  * 31    3/28/97 3:19p Hoffoss
146  * Fixed bug.
147  * 
148  * 30    3/20/97 3:55p Hoffoss
149  * Major changes to how dialog boxes initialize (load) and update (save)
150  * their internal data.  This should simplify things and create less
151  * problems.
152  * 
153  * 29    3/17/97 4:29p Hoffoss
154  * Automated player's wing flaging as a starting player wing.
155  * 
156  * 28    3/12/97 12:40p Hoffoss
157  * Fixed bugs in wing object management functions, several small additions
158  * and rearrangements.
159  * 
160  * 27    3/04/97 6:27p Hoffoss
161  * Changes to Fred to handle new wing structure.
162  * 
163  * 26    2/28/97 11:31a Hoffoss
164  * Implemented modeless dialog saving and restoring, and changed some
165  * variables names.
166  * 
167  * 25    2/27/97 3:16p Allender
168  * major wing structure enhancement.  simplified wing code.  All around
169  * better wing support
170  * 
171  * 24    2/27/97 2:31p Hoffoss
172  * Changed wing create code to bash ship's cues to false.
173  * 
174  * 23    2/24/97 5:38p Hoffoss
175  * Added dialog box to name a wing at creation, code to change ship names
176  * to match wing name, and code to maintain these ship names.
177  * 
178  * 22    2/20/97 4:03p Hoffoss
179  * Several ToDo items: new reinforcement clears arrival cue, reinforcement
180  * control from ship and wing dialogs, show grid toggle.
181  * 
182  * 21    2/17/97 5:28p Hoffoss
183  * Checked RCS headers, added them were missing, changing description to
184  * something better, etc where needed.
185  *
186  * $NoKeywords: $
187  */
188
189 #include "stdafx.h"
190 #include "fred.h"
191 #include "freddoc.h"
192 #include "fredview.h"
193 #include "3d.h"
194 #include "physics.h"
195 #include "object.h"
196 #include "editor.h"
197 #include "ailocal.h"
198 #include "ship.h"
199 #include "vecmat.h"
200 #include "management.h"
201 #include "linklist.h"
202 #include "mainfrm.h"
203 #include "wing.h"
204 #include "createwingdlg.h"
205 #include "management.h"
206
207 #define MULTI_WING      999999
208
209 #ifdef _DEBUG
210 #define new DEBUG_NEW
211 #undef THIS_FILE
212 static char THIS_FILE[] = __FILE__;
213 #endif
214
215 int already_deleting_wing = 0;
216
217 void remove_player_from_wing(int player, int min = 1);
218
219 // Finds a free wing slot (i.e. unused)
220 int find_free_wing()
221 {
222         int i;
223
224         for (i=0; i<MAX_WINGS; i++)
225                 if (!Wings[i].wave_count)
226                         return i;
227
228         return -1;
229 }
230
231 int check_wing_dependencies(int wing_num)
232 {
233         char *name;
234
235         name = Wings[wing_num].name;
236         return reference_handler(name, REF_TYPE_WING, -1);
237 }
238
239 void mark_wing(int wing)
240 {
241         int i;
242
243         unmark_all();
244         SDL_assert(Wings[wing].special_ship >= 0 && Wings[wing].special_ship < Wings[wing].wave_count);
245         set_cur_object_index(wing_objects[wing][Wings[wing].special_ship]);
246         for (i=0; i<Wings[wing].wave_count; i++)
247                 mark_object(wing_objects[wing][i]);
248 }
249
250 // delete a whole wing, also deleting it's ships if necessary.
251 int delete_wing(int wing_num, int bypass)
252 {
253         int i, r, total;
254
255         if (already_deleting_wing)
256                 return 0;
257
258         r = check_wing_dependencies(wing_num);
259         if (r)
260                 return r;
261
262         already_deleting_wing = 1;
263         for (i=0; i<Num_reinforcements; i++)
264                 if (!stricmp(Wings[wing_num].name, Reinforcements[i].name)) {
265                         delete_reinforcement(i);
266                         break;
267                 }
268
269         invalidate_references(Wings[wing_num].name, REF_TYPE_WING);
270         if (!bypass) {
271                 total = Wings[wing_num].wave_count;
272                 for (i=0; i<total; i++)
273                         delete_object(wing_objects[wing_num][i]);
274         }
275
276         Wings[wing_num].wave_count = 0;
277         if (cur_wing == wing_num)
278                 set_cur_wing(cur_wing = -1);  // yes, one '=' is correct.
279
280         free_sexp2(Wings[wing_num].arrival_cue);
281         free_sexp2(Wings[wing_num].departure_cue);
282
283         num_wings--;
284         set_modified();
285         already_deleting_wing = 0;
286         return 0;
287 }
288
289 // delete a whole wing, leaving ships intact but wingless.
290 void remove_wing(int wing_num)
291 {
292         int i, total;
293         object *ptr;
294
295         if (check_wing_dependencies(wing_num))
296                 return;
297
298         Ship_editor_dialog.bypass_errors = Wing_editor_dialog.bypass_errors = 1;
299         Ship_editor_dialog.update_data(0);
300         total = Wings[wing_num].wave_count;
301         for (i=0; i<total; i++) {
302                 ptr = &Objects[wing_objects[wing_num][i]];
303                 if (ptr->type == OBJ_SHIP)
304                         remove_ship_from_wing(ptr->instance);
305                 else if (ptr->type == OBJ_START)
306                         remove_player_from_wing(ptr->instance);
307         }
308
309         SDL_assert(!Wings[wing_num].wave_count);
310         Ship_editor_dialog.initialize_data(1);
311         Ship_editor_dialog.bypass_errors = Wing_editor_dialog.bypass_errors = 0;
312
313         if (cur_wing == wing_num) {
314                 set_cur_wing(cur_wing = -1);  // yes, one '=' is correct.
315         }
316
317         set_modified();
318 }
319
320 // Takes a ship out of a wing, deleting wing if that was the only ship in it.
321 void remove_ship_from_wing(int ship, int min)
322 {
323         char buf[256];
324         int i, wing, end, obj;
325
326         wing = Ships[ship].wingnum;
327         if (wing != -1) {
328                 if (Wings[wing].wave_count == min) {
329                         Wings[wing].wave_count = 0;
330                         delete_wing(wing);
331
332                 } else {
333                         i = Wings[wing].wave_count;
334                         end = i - 1;
335                         while (i--)
336                                 if (wing_objects[wing][i] == Ships[ship].objnum)
337                                         break;
338
339                         SDL_assert(i != -1);  // Error, object should be in wing.
340                         if (Wings[wing].special_ship == i)
341                                 Wings[wing].special_ship = 0;
342
343                         // if not last element, move last element to position to fill gap
344                         if (i != end) {
345                                 obj = wing_objects[wing][i] = wing_objects[wing][end];
346                                 Wings[wing].ship_index[i] = Wings[wing].ship_index[end];
347                                 if (Objects[obj].type == OBJ_SHIP) {
348                                         sprintf(buf, "%s %d", Wings[wing].name, i + 1);
349                                         rename_ship(Wings[wing].ship_index[i], buf);
350                                 }
351                         }
352
353                         Wings[wing].wave_count--;
354                         if (Wings[wing].wave_count && (Wings[wing].threshold >= Wings[wing].wave_count))
355                                 Wings[wing].threshold = Wings[wing].wave_count - 1;
356                 }
357
358                 Ships[ship].wingnum = -1;
359         }
360
361         set_modified();
362         // reset ship name to non-wing default ship name
363         sprintf(buf, "%s %d", Ship_info[Ships[ship].ship_info_index].name, ship);
364         rename_ship(ship, buf);
365 }
366
367 // Takes a player out of a wing, deleting wing if that was the only ship in it.
368 void remove_player_from_wing(int player, int min)
369 {
370         remove_ship_from_wing(player, min);
371 }
372
373 // Forms a wing from marked objects
374 int create_wing()
375 {
376         char msg[1024];
377         int i, ship, wing = -1, waypoints = 0, count = 0, illegal_ships = 0;
378         int friendly, hostile, leader;
379         object *ptr;
380         create_wing_dlg dlg;
381
382         if (!query_valid_object())
383                 return -1;
384
385         leader = cur_object_index;
386         ptr = GET_FIRST(&obj_used_list);
387         while (ptr != END_OF_LIST(&obj_used_list)) {
388                 if ((ptr->type == OBJ_SHIP) && (ptr->flags & OF_MARKED)) {
389                         count++;
390                         i = -1;
391                         switch (ptr->type) {
392                                 case OBJ_SHIP:
393                                 case OBJ_START:
394                                         i = Ships[ptr->instance].wingnum;
395                                         break;
396                         }
397
398                         if (i >= 0) {
399                                 if (wing < 0)
400                                         wing = i;
401                                 else if (wing != i)
402                                         wing = MULTI_WING;
403                         }
404                 }
405
406                 ptr = GET_NEXT(ptr);
407         }
408
409         if (count > MAX_SHIPS_PER_WING) {
410                 sprintf(msg, "You have too many ships marked!\n"
411                         "A wing is limited to %d ships total", MAX_SHIPS_PER_WING);
412
413                 Fred_main_wnd->MessageBox(msg, "Error", MB_ICONEXCLAMATION);
414                 return -1;
415         }
416
417         if ((wing >= 0) && (wing != MULTI_WING)) {
418                 sprintf(msg, "Do you want to reform wing \"%s\"?", Wings[wing].name);
419                 i = Fred_main_wnd->MessageBox(msg, "Query", MB_YESNOCANCEL);
420                 if (i == IDCANCEL)
421                         return -1;
422
423                 else if (i == IDNO)
424                         wing = -1;
425
426                 else {  // must be IDYES
427                         for (i=Wings[wing].wave_count-1; i>=0; i--) {
428                                 ptr = &Objects[wing_objects[wing][i]];
429                                 switch (ptr->type) {
430                                         case OBJ_SHIP:
431                                                 remove_ship_from_wing(ptr->instance, 0);
432                                                 break;
433
434                                         case OBJ_START:
435                                                 remove_player_from_wing(ptr->instance, 0);
436                                                 break;
437
438                                         default:
439                                                 Int3();  // shouldn't be in a wing!
440                                 }
441                         }
442
443                         SDL_assert(!Wings[wing].wave_count);
444                         num_wings--;
445                 }
446
447         } else
448                 wing = -1;
449
450         if (wing < 0) {
451                 wing = find_free_wing();
452                 Wings[wing].num_waves = 1;
453                 Wings[wing].threshold = 0;
454                 Wings[wing].arrival_location = Wings[wing].departure_location = 0;
455                 Wings[wing].arrival_distance = 0;
456                 Wings[wing].arrival_anchor = -1;
457                 Wings[wing].arrival_cue = Locked_sexp_true;
458                 Wings[wing].departure_cue = Locked_sexp_false;
459                 Wings[wing].hotkey = -1;
460                 Wings[wing].flags = 0;
461
462                 for (i=0; i<MAX_AI_GOALS; i++) {
463                         Wings[wing].ai_goals[i].ai_mode = AI_GOAL_NONE;
464                         Wings[wing].ai_goals[i].priority = -1;                          // this sets up the priority field to be like ships
465                 }
466
467                 if (wing < 0) {
468                         Fred_main_wnd->MessageBox("Too many wings, can't create more!",
469                                 "Error", MB_ICONEXCLAMATION);
470
471                         return -1;
472                 }
473
474                 if (dlg.DoModal() == IDCANCEL)
475                         return -1;
476
477                 string_copy(Wings[wing].name, dlg.m_name, NAME_LENGTH - 1);
478         }
479
480         set_cur_indices(-1);
481         ptr = GET_FIRST(&obj_used_list);
482         while (ptr != END_OF_LIST(&obj_used_list)) {
483                 if (ptr->flags & OF_MARKED) {
484 //                      if ((ptr->type == OBJ_START) && (ptr->instance)) {
485 //                              starts++;
486 //                              unmark_object(OBJ_INDEX(ptr));
487
488 //                      } else if (ptr->type == OBJ_WAYPOINT) {
489                         if (ptr->type == OBJ_WAYPOINT) {
490                                 waypoints++;
491                                 unmark_object(OBJ_INDEX(ptr));
492
493                         } else if (ptr->type == OBJ_SHIP) {
494                                 switch (ship_query_general_type(ptr->instance))
495                                 {
496                                         case SHIP_TYPE_FIGHTER_BOMBER:
497                                         case SHIP_TYPE_CRUISER:
498                                         case SHIP_TYPE_AWACS:
499                                         case SHIP_TYPE_GAS_MINER:
500                                         case SHIP_TYPE_CORVETTE:
501                                         case SHIP_TYPE_FREIGHTER:
502                                         case SHIP_TYPE_CAPITAL:
503                                         case SHIP_TYPE_TRANSPORT:
504                                         case SHIP_TYPE_SUPERCAP:
505                                                 break;
506
507                                         default:
508                                                 illegal_ships++;
509                                                 unmark_object(OBJ_INDEX(ptr));
510                                 }
511                         }
512                 }
513
514                 ptr = GET_NEXT(ptr);
515         }
516
517         // if this wing is a player starting wing, automatically set the hotkey for this wing
518         for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
519                 if ( !stricmp(Wings[wing].name, Starting_wing_names[i]) ) {
520                         Wings[wing].hotkey = i;
521                         break;
522                 }
523         }
524
525         count = friendly = hostile = 0;
526         if (Objects[Ships[Player_start_shipnum].objnum].flags & OF_MARKED)
527                 count = 1;
528
529         ptr = GET_FIRST(&obj_used_list);
530         while (ptr != END_OF_LIST(&obj_used_list)) {
531                 if (ptr->flags & OF_MARKED) {
532                         if ((ptr->type == OBJ_START) && (ptr->instance == Player_start_shipnum))
533                                 i = 0;  // player 1 start always goes to front of the wing
534                         else
535                                 i = count++;
536
537                         SDL_assert((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START));
538                         ship = ptr->instance;
539                         if (Ships[ship].wingnum != -1) {
540                                 if (ptr->type == OBJ_SHIP)
541                                         remove_ship_from_wing(ship);
542                                 else
543                                         remove_player_from_wing(ptr->instance);
544                         }
545
546                         sprintf(msg, "%s %d", Wings[wing].name, i + 1);
547                         rename_ship(ship, msg);
548                         if (Ships[ship].team == TEAM_FRIENDLY)
549                                 friendly = 1;
550                         else if ((Ships[ship].team == TEAM_HOSTILE) || (Ships[ship].team == TEAM_NEUTRAL))
551                                 hostile = 1;
552
553                         Wings[wing].ship_index[i] = ship;
554                         Ships[ship].wingnum = wing;
555                         if (Ships[ship].arrival_cue >= 0)
556                                 free_sexp2(Ships[ship].arrival_cue);
557
558                         Ships[ship].arrival_cue = Locked_sexp_false;
559                         if (Ships[ship].departure_cue >= 0)
560                                 free_sexp2(Ships[ship].departure_cue);
561
562                         Ships[ship].departure_cue = Locked_sexp_false;
563
564                         wing_objects[wing][i] = OBJ_INDEX(ptr);
565                         if (OBJ_INDEX(ptr) == leader)
566                                 Wings[wing].special_ship = i;
567                 }
568
569                 ptr = GET_NEXT(ptr);
570         }
571
572         if (!count)  // this should never happen, so if it does, needs to be fixed now.
573                 Error(LOCATION, "No valid ships were selected to form wing from");
574
575         Wings[wing].wave_count = count;
576         num_wings++;
577
578 //      if (starts)
579 //              Fred_main_wnd->MessageBox("Multi-player starting points can't be part of a wing!\n"
580 //                      "All marked multi-player starting points were ignored",
581 //                      "Error", MB_ICONEXCLAMATION);
582
583         if (waypoints)
584                 Fred_main_wnd->MessageBox("Waypoints can't be part of a wing!\n"
585                         "All marked waypoints were ignored",
586                         "Error", MB_ICONEXCLAMATION);
587
588         if (illegal_ships)
589                 Fred_main_wnd->MessageBox("Some ship types aren't allowed to be in a wing.\n"
590                         "All marked ships of these types were ignored",
591                         "Error", MB_ICONEXCLAMATION);
592
593         if (friendly && hostile)
594                 Fred_main_wnd->MessageBox("Both hostile and friendly ships in same wing", "Warning");
595
596         mark_wing(wing);
597         return 0;
598 }
599
600 /////////////////////////////////////////////////////////////////////////////////////
601 // Old stuff down there..
602
603 #define MAX_WING_VECTORS        8       //      8 vectors per wing formation.  Possible to have more
604                                                                 //      than 8 ships.  A vector is where a ship is located relative
605                                                                 //      to the leader.  Other ships can be located at the same
606                                                                 //      vector relative to another member.  So wing formation
607                                                                 //      size is not limited by this constant.
608 #define MAX_WING_FORMATIONS     8       //      8 different kinds of wing formations
609
610 typedef struct formation {
611         int             num_vectors;
612         vector  offsets[MAX_WING_VECTORS];
613 } formation;
614
615 formation Wing_formations[MAX_WING_FORMATIONS];
616
617 //wing  Wings[MAX_WINGS];
618
619 int     Wings_initialized = 0;
620
621 void initialize_wings(void)
622 {
623         if (Wings_initialized)
624                 return;
625
626         Wings_initialized = 1;
627
628         Wing_formations[0].num_vectors = 2;
629         
630         Wing_formations[0].offsets[0].x = -5.0f;
631         Wing_formations[0].offsets[0].y = +1.0f;
632         Wing_formations[0].offsets[0].z = -5.0f;
633
634         Wing_formations[0].offsets[1].x = +5.0f;
635         Wing_formations[0].offsets[1].y = +1.0f;
636         Wing_formations[0].offsets[1].z = -5.0f;
637 }
638
639 void create_wings_from_objects(void)
640 {
641         int     i;
642
643         for (i=0; i<MAX_WINGS; i++)
644                 Wings[i].wave_count= 0;
645
646         for (i=0; i<MAX_OBJECTS; i++)
647                 if (Objects[i].type != OBJ_NONE)
648                         if (get_wingnum(i) != -1) {
649                                 int     wingnum = get_wingnum(i);
650                                 
651                                 SDL_assert((wingnum >= 0) && (wingnum < MAX_WINGS));
652                                 SDL_assert(Wings[wingnum].wave_count < MAX_SHIPS_PER_WING);
653 // JEH                  strcpy(Wings[wingnum].ship_names[Wings[wingnum].count++], i;
654                         }
655
656 }
657
658 int get_free_objnum(void)
659 {
660         int     i;
661
662         for (i=1; i<MAX_OBJECTS; i++)
663                 if (Objects[i].type == OBJ_NONE)
664                         return i;
665
666         return -1;
667 }
668
669 //      Create a wing.
670 //      wing_type is the type of wing from the Wing_formations array to create.
671 //      leader_index is the index in Objects of the leader object.  This object must
672 //      have a position and an orientation.
673 //      *wingmen is a list of indices of existing ships to be added to the wing.
674 //      The wingmen list is terminated by -1.
675 //      max_size is the maximum number of ships to add to the wing
676 //      fill_flag is set if more ships are to be added to fill out the wing to max_size
677 void create_wing(int wing_type, int leader_index, int *wingmen, int max_size, int fill_flag)
678 {
679         int                     num_placed, num_vectors, cur_vec_index;
680         object          *lobjp = &Objects[leader_index];
681         formation       *wingp;
682         object          *parent;
683         int                     wing_list[MAX_OBJECTS];
684         matrix          rotmat;
685
686         initialize_wings();
687
688         SDL_assert((wing_type >= 0) && (wing_type < MAX_WING_FORMATIONS));
689         SDL_assert(Wing_formations[wing_type].num_vectors > 0);
690         SDL_assert(Wing_formations[wing_type].num_vectors < MAX_WING_VECTORS);
691
692         SDL_assert(Objects[leader_index].type != OBJ_NONE);
693         SDL_assert(max_size < MAX_SHIPS_PER_WING);
694
695         num_placed = 0;
696         wingp = &Wing_formations[wing_type];
697         num_vectors = wingp->num_vectors;
698         cur_vec_index = 0;
699         parent = lobjp;
700         vm_copy_transpose_matrix(&rotmat, &lobjp->orient);
701
702         while (num_placed < max_size) {
703                 vector  wvec;
704                 int             curobj;
705
706                 if (*wingmen == -1) {
707                         if (!fill_flag)
708                                 break;
709                         else {
710                                 curobj = get_free_objnum();
711                                 SDL_assert(curobj != -1);
712                                 Objects[curobj].type = lobjp->type;
713                                 SDL_assert(Wings[cur_wing].wave_count < MAX_SHIPS_PER_WING);
714 // JEH          Wings[cur_wing].ship_list[Wings[cur_wing].count] = curobj;
715                                 Wings[cur_wing].wave_count++;
716                         }
717                 } else
718                         curobj = *wingmen++;
719
720                 Objects[curobj] = *lobjp;
721                 vm_vec_rotate(&wvec, &wingp->offsets[cur_vec_index], &rotmat);
722                 cur_vec_index = (cur_vec_index + 1) % num_vectors;
723                 
724                 if (num_placed < num_vectors)
725                         parent = lobjp;
726                 else
727                         parent = &Objects[wing_list[num_placed - num_vectors]];
728                 
729                 wing_list[num_placed] = curobj;
730
731                 vm_vec_add(&Objects[curobj].pos, &parent->pos, &wvec);
732
733                 num_placed++;
734         }
735
736 }
737
738 //      Create a wing.
739 //      cur_object_index becomes the leader.
740 //      If count == -1, then all objects of wing cur_wing get added to the wing.
741 //      If count == +n, then n objects are added to the wing.
742 void test_form_wing(int count)
743 {
744         int     i, wingmen[MAX_OBJECTS];
745         int     j, fill_flag;
746
747         j = 0;
748
749         SDL_assert(cur_object_index != -1);
750         SDL_assert(Objects[cur_object_index].type != OBJ_NONE);
751         SDL_assert(get_wingnum(cur_object_index) != -1);
752         get_wingnum(cur_object_index);
753
754         wingmen[0] = -1;
755
756         for (i=1; i<MAX_OBJECTS; i++)
757                 if ((get_wingnum(i) == cur_wing) && (Objects[i].type != OBJ_NONE))
758                         if (i != cur_object_index)
759                                 wingmen[j++] = i;
760         
761         wingmen[j] = -1;
762
763         fill_flag = 0;
764
765         if (count > 0) {
766                 fill_flag = 1;
767                 j += count;
768         }
769
770         set_wingnum(cur_object_index, cur_wing);
771         create_wing(0, cur_object_index, wingmen, j, fill_flag);
772 }