]> icculus.org git repositories - taylor/freespace2.git/blob - src/missionui/missionshipchoice.cpp
GCC 3.4 fixes.
[taylor/freespace2.git] / src / missionui / missionshipchoice.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/MissionUI/MissionShipChoice.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module to allow player ship selection for the mission
16  *
17  * $Log$
18  * Revision 1.5  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.4  2003/05/25 02:30:43  taylor
22  * Freespace 1 support
23  *
24  * Revision 1.3  2002/06/17 06:33:09  relnev
25  * ryan's struct patch for gcc 2.95
26  *
27  * Revision 1.2  2002/06/09 04:41:23  relnev
28  * added copyright header
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:10  root
31  * Initial import.
32  *
33  * 
34  * 26    11/02/99 3:23p Jefff
35  * "x Meters" to "x Meter" in German
36  * 
37  * 25    8/05/99 3:40p Jefff
38  * hi-res text adjustments
39  * 
40  * 24    8/04/99 11:56a Jefff
41  * fixed gamma wing hi-res coordinate error.  fixed
42  * ss_load_individual_animation to load anis from a packfile.
43  * 
44  * 23    7/30/99 4:22p Andsager
45  * restored ship and weapon anim sounds for demo.  Added sound for
46  * changing ship in weapon loadout screen.
47  * 
48  * 22    7/28/99 12:23p Jefff
49  * updated hi-res wing icon coords
50  * 
51  * 21    7/21/99 3:24p Andsager
52  * Modify demo to use 2 frame ship and weapon select anis and cut sounds
53  * associated with ani
54  * 
55  * 20    7/16/99 2:23p Anoop
56  * Fixed build error.
57  * 
58  * 19    7/16/99 1:49p Dave
59  * 8 bit aabitmaps. yay.
60  * 
61  * 18    7/15/99 6:36p Jamesa
62  * Moved default ship name into the ships.tbl
63  * 
64  * 17    7/15/99 9:20a Andsager
65  * FS2_DEMO initial checkin
66  * 
67  * 16    6/29/99 7:39p Dave
68  * Lots of small bug fixes.
69  * 
70  * 15    6/04/99 11:32a Dave
71  * Added reset text to ship select screen. Fixed minor xstr bug in ui
72  * window
73  * 
74  * 14    3/23/99 9:26p Neilk
75  * fixed various multiplayer lock button problems
76  * 
77  * 13    3/23/99 11:55a Neilk
78  * new support for ship anis
79  * 
80  * 14    3/15/99 6:27p Neilk
81  * Added hires support for the ship animations
82  * 
83  * 13    3/15/99 11:18a Neilk
84  * Modified animation code so ship animations loop back to frame 51
85  * 
86  * 12    3/12/99 12:02p Davidg
87  * Modified coordinates for low res ship animations for new artwork
88  * 
89  * 11    3/10/99 6:21p Neilk
90  * Added new artwork for hires
91  * 
92  * 10    2/21/99 6:01p Dave
93  * Fixed standalone WSS packets. 
94  * 
95  * 9     2/18/99 11:46a Neilk
96  * hires interface coord support
97  * 
98  * 8     2/11/99 3:08p Dave
99  * PXO refresh button. Very preliminary squad war support.
100  * 
101  * 7     2/01/99 5:55p Dave
102  * Removed the idea of explicit bitmaps for buttons. Fixed text
103  * highlighting for disabled gadgets.
104  * 
105  * 6     1/29/99 4:17p Dave
106  * New interface screens.
107  * 
108  * 5     12/18/98 1:13a Dave
109  * Rough 1024x768 support for Direct3D. Proper detection and usage through
110  * the launcher.
111  * 
112  * 4     11/30/98 1:07p Dave
113  * 16 bit conversion, first run.
114  * 
115  * 3     10/13/98 9:28a Dave
116  * Started neatening up freespace.h. Many variables renamed and
117  * reorganized. Added AlphaColors.[h,cpp]
118  * 
119  * 2     10/07/98 10:53a Dave
120  * Initial checkin.
121  * 
122  * 1     10/07/98 10:50a Dave
123  * 
124  * 102   9/11/98 4:14p Dave
125  * Fixed file checksumming of < file_size. Put in more verbose kicking and
126  * PXO stats store reporting.
127  * 
128  * 101   6/09/98 10:31a Hoffoss
129  * Created index numbers for all xstr() references.  Any new xstr() stuff
130  * added from here on out should be added to the end if the list.  The
131  * current list count can be found in FreeSpace.cpp (search for
132  * XSTR_SIZE).
133  * 
134  * 100   6/01/98 11:43a John
135  * JAS & MK:  Classified all strings for localization.
136  * 
137  * 99    5/23/98 5:50p Lawrance
138  * Don't reset scroll offset when rebuilding the list
139  * 
140  * 98    5/06/98 11:50p Lawrance
141  * Clean up help overlay code for loadout screens
142  * 
143  * 97    4/30/98 6:03p Lawrance
144  * Make drag and drop work better.
145  * 
146  * 96    4/29/98 3:31p Lawrance
147  * draw disabled frames for icons when appropriate
148  * 
149  * 95    4/28/98 9:35a Dave
150  * Remove bogus assert in create_wings() for ships which arrive late and
151  * haven't been created yet.
152  * 
153  * 94    4/27/98 6:02p Dave
154  * Modify how missile scoring works. Fixed a team select ui bug. Speed up
155  * multi_lag system. Put in new main hall.
156  * 
157  * 93    4/14/98 12:57a Dave
158  * Made weapon select screen show netplayer names above ships. Fixed pilot
159  * info popup to show the status of pilot images more correctly.
160  * 
161  * 92    4/13/98 3:27p Lawrance
162  * fix coords for ship selection pool numbers
163  * 
164  * 91    4/13/98 3:11p Andsager
165  * Fixed bug when there is no description for a ship.
166  * 
167  * 90    4/10/98 4:51p Hoffoss
168  * Made several changes related to tooltips.
169  * 
170  * 89    4/05/98 7:43p Lawrance
171  * fix up saving/restoring of link status and auto-target/match-speed.
172  * 
173  * 88    4/03/98 4:16p Adam
174  * changed coord's and skip frame for new SS animations
175  * 
176  * 87    4/02/98 11:40a Lawrance
177  * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
178  * 
179  * 86    4/01/98 11:19p Dave
180  * Put in auto-loading of xferred pilot pic files. Grey out background
181  * behind pinfo popup. Put a chatbox message in when players are kicked.
182  * Moved mission title down in briefing. Other ui fixes.
183  * 
184  * 85    4/01/98 9:21p John
185  * Made NDEBUG, optimized build with no warnings or errors.
186  * 
187  * 84    3/31/98 11:47p Lawrance
188  * Fix some bugs related to wingmen selection when doing a quick mission
189  * restart.
190  * 
191  * 83    3/31/98 1:50p Duncan
192  * ALAN: fix bugs with selecting alternate weapons 
193  * 
194  * 82    3/30/98 12:18a Lawrance
195  * change some DEMO_RELEASE code to not compile code rather than return
196  * early
197  * 
198  * 81    3/29/98 12:55a Lawrance
199  * Get demo build working with limited set of data.
200  * 
201  * 80    3/26/98 6:01p Dave
202  * Put in file checksumming routine in cfile. Made pilot pic xferring more
203  * robust. Cut header size of voice data packets in half. Put in
204  * restricted game host query system.
205  * 
206  * 79    3/25/98 8:43p Hoffoss
207  * Changed anim_play() to not be so damn complex when you try and call it.
208  * 
209  * 78    3/12/98 4:03p Lawrance
210  * don't press buttons when icon dropped on them
211  * 
212  * 77    3/09/98 11:13a Lawrance
213  * Fix up drop sound effects used in loadout screens.
214  * 
215  * 76    3/06/98 5:36p Dave
216  * Finished up first rev of team vs team. Probably needs to be debugged
217  * thoroughly.
218  * 
219  * 75    3/05/98 6:48p Lawrance
220  * reposition commit_pressed() to ensure popup gets called after clear but
221  * before flip
222  * 
223  * 74    3/05/98 5:03p Dave
224  * More work on team vs. team support for multiplayer. Need to fix bugs in
225  * weapon select.
226  * 
227  * 73    3/05/98 12:38a Lawrance
228  * Fix bug with flashing buttons showing over help overlay
229  * 
230  * 72    3/02/98 5:42p John
231  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
232  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
233  * model_caching be on by default.  Made each cached model have it's own
234  * bitmap id.  Made asteroids not rotate when model_caching is on.  
235  * 
236  * 71    3/01/98 3:26p Dave
237  * Fixed a few team select bugs. Put in multiplayer intertface sounds.
238  * Corrected how ships are disabled/enabled in team select/weapon select
239  * screens.
240  * 
241  * 70    2/28/98 7:04p Lawrance
242  * Don't show reset button in multiplayer
243  * 
244  * 69    2/26/98 8:21p Allender
245  * fix compiler warning
246  * 
247  * 68    2/26/98 4:59p Allender
248  * groundwork for team vs team briefings.  Moved weaponry pool into the
249  * Team_data structure.  Added team field into the p_info structure.
250  * Allow for mutliple structures in the briefing code.
251  * 
252  * 67    2/24/98 6:21p Lawrance
253  * Integrate new reset button into loadout screens
254  * 
255  * 66    2/22/98 4:30p John
256  * More string externalization classification
257  * 
258  * 65    2/22/98 4:17p John
259  * More string externalization classification... 190 left to go!
260  * 
261  * 64    2/22/98 12:19p John
262  * Externalized some strings
263  * 
264  * 63    2/19/98 6:26p Dave
265  * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
266  * initial support for player data uploading.
267  * 
268  * 62    2/18/98 3:56p Dave
269  * Several bugs fixed for mp team select screen. Put in standalone packet
270  * routing for team select.
271  * 
272  * 61    2/17/98 6:07p Dave
273  * Tore out old multiplayer team select screen, installed new one.
274  * 
275  * 60    2/13/98 3:46p Dave
276  * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
277  * functions.
278  * 
279  * 59    2/12/98 2:38p Allender
280  * fix multiplayer primary/secondary weapon problems when ships are
281  * outfitted with less than max number
282  * 
283  * 58    2/07/98 5:47p Lawrance
284  * reset flashing if a button gets highlighted
285  * 
286  * 57    2/05/98 11:21p Lawrance
287  * When flashing buttons, use highlight frame
288  * 
289  * 56    1/30/98 10:00a Allender
290  * made large ships able to attack other ships.  Made goal code recognize
291  * when ships removed from wings during ship select
292  * 
293  * 55    1/22/98 5:26p Dave
294  * Modified some pregame sequencing packets. Starting to repair broken
295  * standalone stuff.
296  * 
297  * 54    1/17/98 2:46a Dave
298  * Reworked multiplayer join/accept process. Ingame join still needs to be
299  * integrated.
300  * 
301  * 53    1/15/98 4:11p Lawrance
302  * Add call to check if slot is player occupied.
303  * 
304  * 52    1/13/98 4:47p Allender
305  * change default terran ship to reflect new ship class name
306  * 
307  * 51    1/12/98 5:17p Dave
308  * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
309  * work through the standalone.
310  * 
311  * 50    1/10/98 12:46a Lawrance
312  * Store last_modified time for mission into player loadout struct.
313  * 
314  * 49    1/09/98 6:06p Dave
315  * Put in network sound support for multiplayer ship/weapon select
316  * screens. Made clients exit game correctly through warp effect. Fixed
317  * main hall menu help overlay bug.
318  * 
319  * 48    1/08/98 11:38a Lawrance
320  * correct typo
321  * 
322  * 47    1/08/98 11:36a Lawrance
323  * Get ship select and weapons loadout icon dropping sound effects working
324  * for single and multiplayer
325  * 
326  * 46    1/02/98 9:10p Lawrance
327  * Big changes to how colors get set on the HUD.
328  * 
329  * 45    12/29/97 4:21p Lawrance
330  * Flash buttons on briefing/ship select/weapons loadout when enough time
331  * has elapsed without activity.
332  * 
333  * 44    12/29/97 9:42a Lawrance
334  * Ensure that WING_SLOT_IS_PLAYER gets set correctly in multiplayer.
335  * 
336  * 43    12/24/97 8:54p Lawrance
337  * Integrating new popup code
338  * 
339  * 42    12/24/97 1:19p Lawrance
340  * fix some bugs with the multiplayer ship/weapons loadout
341  * 
342  * 41    12/23/97 5:25p Allender
343  * more fixes to multiplayer ship selection.  Fixed strange reentrant
344  * problem with cf_callback when loading freespace data
345  * 
346  * 40    12/23/97 11:59a Allender
347  * changes to ship/wespon selection for multplayer.  added sounds to some
348  * interface screens.  Update and modiied end-of-briefing packets -- yet
349  * to be tested.
350  * 
351  * 39    12/23/97 11:04a Lawrance
352  * fix bug in ss_swap_slot_slot()
353  * 
354  * 38    12/23/97 10:57a Lawrance
355  * move player_set_weapon_prefs() to when commit is pressed in briefing
356  * (from entering gameplay)
357  * 
358  * 37    12/23/97 10:54a Lawrance
359  * fix some bugs in multiplayer ship selection
360  * 
361  * 36    12/22/97 6:18p Lawrance
362  * Get save/restore of player loadout working with new code
363  * 
364  * 35    12/22/97 1:40a Lawrance
365  * Re-write ship select/weapons loadout to be multiplayer friendly
366  * 
367  * 34    12/19/97 1:23p Dave
368  * Put in multiplayer groundwork for new weapon/ship select screens.
369  * 
370  * $NoKeywords: $
371  *
372 */
373
374 #include "missionscreencommon.h"
375 #include "missionshipchoice.h"
376 #include "missionparse.h"
377 #include "missionbrief.h"
378 #include "freespace.h"
379 #include "gamesequence.h"
380 #include "ship.h"
381 #include "key.h"
382 #include "2d.h"
383 #include "line.h"
384 #include "3d.h"
385 #include "model.h"
386 #include "timer.h"
387 #include "math.h"
388 #include "linklist.h"
389 #include "mouse.h"
390 #include "weapon.h"
391 #include "ui.h"
392 #include "ailocal.h"
393 #include "player.h"
394 #include "audiostr.h"
395 #include "bmpman.h"
396 #include "palman.h"
397 #include "snazzyui.h"
398 #include "animplay.h"
399 #include "packunpack.h"
400 #include "missionweaponchoice.h"
401 #include "contexthelp.h"
402 #include "gamesnd.h"
403 #include "sound.h"
404 #include "missionhotkey.h"
405 #include "multi.h"
406 #include "multimsgs.h"
407 #include "missionload.h"
408 #include "eventmusic.h"
409 #include "chatbox.h"
410 #include "popup.h"
411 #include "multiui.h"
412 #include "multiteamselect.h"
413 #include "multiutil.h"
414 #include "hudwingmanstatus.h"
415 #include "alphacolors.h"
416 #include "localize.h"
417
418 //////////////////////////////////////////////////////
419 // Game-wide Globals
420 //////////////////////////////////////////////////////
421 char default_player_ship[255] = NOX("GTF Ulysses");
422 int Select_default_ship = 0;
423 int Ship_select_open = 0;       // This game-wide global flag is set to 1 to indicate that the ship
424                                                                         // select screen has been opened and memory allocated.  This flag
425                                                                         // is needed so we can know if ship_select_close() needs to called if
426                                                                         // restoring a game from the Options screen invoked from ship select
427
428 int Commit_pressed;     // flag to indicate that the commit button was pressed
429                                                         // use a flag, so the ship_create() can be done at the end of the loop
430
431 //////////////////////////////////////////////////////
432 // Module Globals
433 //////////////////////////////////////////////////////
434 static int Ship_anim_class = -1;                // ship class that is playing as an animation
435 static int Ss_delta_x, Ss_delta_y;      // used to offset the carried icon to make it smoothly leave static position
436
437 //////////////////////////////////////////////////////
438 // UI Data structs
439 //////////////////////////////////////////////////////
440 typedef struct ss_icon_info
441 {
442         int                             icon_bmaps[NUM_ICON_FRAMES];
443         int                             current_icon_bitmap;
444         anim_t                          *anim;
445         anim_instance_t *anim_instance;
446 } ss_icon_info;
447
448 typedef struct ss_slot_info
449 {
450         int status;                     // slot status (WING_SLOT_DISABLED, etc)
451         int sa_index;           // index into ship arrival list, -1 if ship is created
452         int original_ship_class;
453 } ss_slot_info;
454
455 typedef struct ss_wing_info
456 {
457         int num_slots;
458         int wingnum;
459         int is_late;
460         ss_slot_info ss_slots[MAX_WING_SLOTS];
461 } ss_wing_info;
462
463 //ss_icon_info  Ss_icons[MAX_SHIP_TYPES];               // holds ui info on different ship icons
464 //ss_wing_info  Ss_wings[MAX_WING_BLOCKS];              // holds ui info for wings and wing slots
465
466 ss_wing_info    Ss_wings_teams[MAX_TEAMS][MAX_WING_BLOCKS];
467 ss_wing_info    *Ss_wings;
468
469 ss_icon_info    Ss_icons_teams[MAX_TEAMS][MAX_SHIP_TYPES];
470 ss_icon_info    *Ss_icons;
471
472 int Ss_mouse_down_on_region = -1;
473
474 int Selected_ss_class;  // set to ship class of selected ship, -1 if none selected
475 int Hot_ss_icon;                        // index that icon is over in list (0..4)
476 int Hot_ss_slot;                        // index for slot that mouse is over (0..11)
477
478 ////////////////////////////////////////////////////////////
479 // Ship Select UI
480 ////////////////////////////////////////////////////////////
481 UI_WINDOW       Ship_select_ui_window;  
482
483 static int Ship_anim_coords[GR_NUM_RESOLUTIONS][2] = {
484         {
485 #ifdef MAKE_FS1
486                 10, 77
487 #else
488                 257, 84         // GR_640
489 #endif
490         },
491         {
492                 412, 135        // GR_1024
493         }
494 };
495
496 #ifndef MAKE_FS1
497 static int Ship_info_coords[GR_NUM_RESOLUTIONS][2] = {
498         {
499                 28, 78                          // GR_640
500         },
501         {
502                 45, 125                         // GR_1024
503         }
504 };
505 #endif
506
507 // coordinate lookup indicies
508 #define SHIP_SELECT_X_COORD 0
509 #define SHIP_SELECT_Y_COORD 1
510 #define SHIP_SELECT_W_COORD 2
511 #define SHIP_SELECT_H_COORD 3
512
513
514 // NK: changed from 37 to 51 for new FS2 animations
515 #if defined(FS2_DEMO) || defined(FS1_DEMO)
516 #define SHIP_ANIM_LOOP_FRAME    0
517 #elif MAKE_FS1
518 #define SHIP_ANIM_LOOP_FRAME    36
519 #else
520 #define SHIP_ANIM_LOOP_FRAME    51
521 #endif
522
523 #define MAX_ICONS_ON_SCREEN     4
524
525 // (x,y) pairs for ship icon and ship icon number
526 int Ship_list_coords[GR_NUM_RESOLUTIONS][MAX_ICONS_ON_SCREEN][4] = {
527         {
528                 {23,331,4,341},
529                 {23,361,4,371},
530                 {23,391,4,401},
531                 {23,421,4,431}
532         },
533         {
534                 {29,530,10,540},
535                 {29,578,10,588},
536                 {29,626,10,636},
537                 {29,674,10,684}
538         }
539 };
540
541 // Store the x locations for the icons in the wing formations
542 int Wing_icon_coords[GR_NUM_RESOLUTIONS][MAX_WSS_SLOTS][2] = {
543         {
544                 {124,345},
545                 {100,376},
546                 {148,376},
547                 {124,407},
548
549                 {222,345},
550                 {198,376},
551                 {246,376},
552                 {222,407},
553
554                 {320,345},
555                 {296,376},
556                 {344,376},
557                 {320,407}
558         },
559         {
560                 {218,584},
561                 {194,615},
562                 {242,615},
563                 {218,646},
564
565                 {373,584},
566                 {349,615},
567                 {397,615},
568                 {373,646},
569
570                 {531,584},
571                 {507,615},
572                 {555,615},
573                 {531,646}
574         }
575 };
576
577 //////////////////////////////////////////////////////
578 // Linked List of icons to show on ship selection list
579 //////////////////////////////////////////////////////
580 #define SS_ACTIVE_ITEM_USED     (1<<0)
581 typedef struct ss_active_item
582 {
583         ss_active_item  *prev, *next;
584         int                             ship_class;
585         int                             flags;
586 } ss_active_item;
587
588 static ss_active_item   SS_active_head;
589 static ss_active_item   SS_active_items[MAX_WSS_SLOTS];
590
591 static int SS_active_list_start;
592 static int SS_active_list_size;
593
594 //////////////////////////////////////////////////////
595 // Background bitmaps data for ship_select
596 //////////////////////////////////////////////////////
597 static char* Ship_select_background_fname[GR_NUM_RESOLUTIONS] = {
598 #ifdef MAKE_FS1
599         "Brief",
600         "Brief"
601 #else
602         "ShipSelect",
603         "2_ShipSelect"
604 #endif
605 };
606
607 static char* Ship_select_background_mask_fname[GR_NUM_RESOLUTIONS] = {
608         "ShipSelect-m",
609         "2_ShipSelect-m"
610 };
611
612 int Ship_select_background_bitmap;
613
614 //////////////////////////////////////////////////////
615 // Ship select specific buttons
616 //////////////////////////////////////////////////////
617 #define NUM_SS_BUTTONS                          4
618 #define SS_BUTTON_SCROLL_UP             0
619 #define SS_BUTTON_SCROLL_DOWN           1
620 #define SS_BUTTON_RESET                         2
621 #define SS_BUTTON_DUMMY                         3       // needed to capture mouse for drag/drop icons
622
623 // convenient struct for handling all button controls
624 struct ss_buttons {
625         char *filename;
626         int x, y, xt, yt;
627         int hotspot;
628         int scrollable;
629         UI_BUTTON button;  // because we have a class inside this struct, we need the constructor below..
630
631         ss_buttons(char *name, int x1, int y1, int xt1, int yt1, int h, int s) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h), scrollable(s) {}
632 };
633
634 static ss_buttons Ship_select_buttons[GR_NUM_RESOLUTIONS][NUM_SS_BUTTONS] = {
635         {       // GR_640
636 #ifdef MAKE_FS1
637                 ss_buttons("ssb_08",    0,              301,    -1,     -1,     8,      0),     // SCROLL UP
638                 ss_buttons("ssb_09",    0,              453,    -1,     -1,     9,      0),     // SCROLL DOWN
639                 ss_buttons("ssb_39",    566,    317,    -1,     -1,     39,     0),     // RESET
640                 ss_buttons("ssb_39",    0,              0,              -1,     -1,     99,     0)      // dummy for drag n' drop
641 #else
642                 ss_buttons("ssb_08",            5,                      303,    -1,     -1,     8,      0),             // SCROLL UP
643                 ss_buttons("ssb_09",            5,                      454,    -1,     -1,     9,      0),             // SCROLL DOWN
644                 ss_buttons("ssb_39",            571,            347,    -1,     -1,     39,0),          // RESET
645                 ss_buttons("ssb_39",            0,                      0,              -1,     -1,     99,0)                   // dummy for drag n' drop
646 #endif
647         },
648         {       // GR_1024
649                 ss_buttons("2_ssb_08",  8,                      485,    -1,     -1,     8,      0),             // SCROLL UP
650                 ss_buttons("2_ssb_09",  8,                      727,    -1,     -1,     9,      0),             // SCROLL DOWN
651                 ss_buttons("2_ssb_39",  913,            556,    -1,     -1,     39,0),          // RESET
652                 ss_buttons("2_ssb_39",  0,                      0,              -1,     -1,     99,0)                   // dummy for drag n' drop
653         }
654 };
655
656 // ship select text
657 #ifdef MAKE_FS1
658         #define SHIP_SELECT_NUM_TEXT                    0
659 #else
660         #define SHIP_SELECT_NUM_TEXT                    1
661 #endif
662 UI_XSTR Ship_select_text[GR_NUM_RESOLUTIONS][SHIP_SELECT_NUM_TEXT] = {
663         { // GR_640
664                 // not needed for FS1
665 #ifndef MAKE_FS1
666                 { "Reset",                      1337,           580,    337,    UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[0][SS_BUTTON_RESET].button }
667 #endif
668         }, 
669         { // GR_1024
670                 // not needed for FS1
671 #ifndef MAKE_FS1
672                 { "Reset",                      1337,           938,    546,    UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[1][SS_BUTTON_RESET].button }
673 #endif
674         }
675 };
676
677 // Mask bitmap pointer and Mask bitmap_id
678 static bitmap*  ShipSelectMaskPtr;              // bitmap pointer to the ship select mask bitmap
679 static ubyte*   ShipSelectMaskData;             // pointer to actual bitmap data
680 static int              Shipselect_mask_w, Shipselect_mask_h;
681 static int              ShipSelectMaskBitmap;   // bitmap id of the ship select mask bitmap
682
683 static MENU_REGION      Region[NUM_SHIP_SELECT_REGIONS];
684 static int                              Num_mask_regions;
685
686 //////////////////////////////////////////////////////
687 // Drag and Drop variables
688 //////////////////////////////////////////////////////
689 typedef struct ss_carry_icon_info
690 {
691         int from_slot;          // slot index (0..11), -1 if carried from list
692         int ship_class; // ship class of carried icon 
693         int from_x, from_y;
694 } ss_carry_icon_info;
695
696 ss_carry_icon_info Carried_ss_icon;
697
698 ////////////////////////////////////////////////////////////////////
699 // Internal function prototypes
700 ////////////////////////////////////////////////////////////////////
701
702 // render functions
703 void draw_ship_icons();
704 void draw_ship_icon_with_number(int screen_offset, int ship_class);
705 void stop_ship_animation();
706 void start_ship_animation(int ship_class, int play_sound=0);
707
708 // pick-up 
709 int pick_from_ship_list(int screen_offset, int ship_class);
710 void pick_from_wing(int wb_num, int ws_num);
711
712 // ui related
713 void ship_select_button_do(int i);
714 void ship_select_common_init();
715 void ss_reset_selected_ship();
716 void ss_restore_loadout();
717 void maybe_change_selected_wing_ship(int wb_num, int ws_num);
718
719 // init functions
720 void ss_init_pool(team_data *pteam);
721 int create_wings();
722
723 // loading/unloading
724 void ss_unload_icons();
725 void ss_init_units();
726 void unload_ship_anim_instances();
727 void unload_ship_anims();
728 anim* ss_load_individual_animation(int ship_class);
729
730 // Carry icon functions
731 int     ss_icon_being_carried();
732 void    ss_reset_carried_icon();
733 void    ss_set_carried_icon(int from_slot, int ship_class);
734
735 #define SHIP_DESC_X     445
736 #define SHIP_DESC_Y     273
737
738 char *ss_tooltip_handler(char *str)
739 {
740         if (Selected_ss_class < 0)
741                 return NULL;
742
743         if (!stricmp(str, NOX("@ship_name"))) {
744                 return Ship_info[Selected_ss_class].name;
745
746         } else if (!stricmp(str, NOX("@ship_type"))) {
747                 return Ship_info[Selected_ss_class].type_str;
748
749         } else if (!stricmp(str, NOX("@ship_maneuverability"))) {
750                 return Ship_info[Selected_ss_class].maneuverability_str;
751
752         } else if (!stricmp(str, NOX("@ship_armor"))) {
753                 return Ship_info[Selected_ss_class].armor_str;
754
755         } else if (!stricmp(str, NOX("@ship_manufacturer"))) {
756                 return Ship_info[Selected_ss_class].manufacturer_str;
757
758         } else if (!stricmp(str, NOX("@ship_desc"))) {
759                 char *str;
760                 int x, y, w, h;
761
762                 str = Ship_info[Selected_ss_class].desc;
763                 if (!str)
764                         return NULL;
765
766                 gr_get_string_size(&w, &h, str);
767                 x = SHIP_DESC_X - w / 2;
768                 y = SHIP_DESC_Y - h / 2;
769
770                 gr_set_color_fast(&Color_black);
771                 gr_rect(x - 5, y - 5, w + 10, h + 10);
772
773                 gr_set_color_fast(&Color_bright_white);
774                 gr_string(x, y, str);
775                 return NULL;
776         }
777
778         return NULL;
779 }
780
781 // Is an icon being carried?
782 int ss_icon_being_carried()
783 {
784         if ( Carried_ss_icon.ship_class >= 0 ) {
785                 return 1;
786         }
787
788         return 0;
789 }
790
791 // Clear out carried icon info
792 void ss_reset_carried_icon()
793 {
794         Carried_ss_icon.from_slot = -1;
795         Carried_ss_icon.ship_class = -1;
796 }
797
798 // return !0 if carried icon has moved from where it was picked up
799 int ss_carried_icon_moved()
800 {
801         int mx, my;
802
803         mouse_get_pos( &mx, &my );
804         if ( Carried_ss_icon.from_x != mx || Carried_ss_icon.from_y != my) {
805                 return 1;
806         }
807
808         return 0;
809 }
810
811 // Set carried icon data 
812 void ss_set_carried_icon(int from_slot, int ship_class)
813 {
814         Carried_ss_icon.from_slot = from_slot;
815         Carried_ss_icon.ship_class = ship_class;
816
817         // Set the mouse to captured
818         Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.capture_mouse();
819 }
820
821 // clear all active list items, and reset the flags inside the SS_active_items[] array
822 void clear_active_list()
823 {
824         int i;
825         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
826                 SS_active_items[i].flags = 0;
827                 SS_active_items[i].ship_class = -1;
828         }
829         list_init(&SS_active_head);
830
831         SS_active_list_start = 0;
832         SS_active_list_size = 0;
833 }
834
835 // get a free element from SS_active_items[]
836 ss_active_item *get_free_active_list_node()
837 {
838         int i;
839         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
840                 if ( SS_active_items[i].flags == 0 ) {
841                         SS_active_items[i].flags |= SS_ACTIVE_ITEM_USED;
842                         return &SS_active_items[i];
843                 }
844         }
845         return NULL;
846 }
847
848 // add a ship into the active list
849 void active_list_add(int ship_class)
850 {
851         ss_active_item *sai;
852
853         sai = get_free_active_list_node();
854         Assert(sai != NULL);
855         sai->ship_class = ship_class;
856         list_append(&SS_active_head, sai);
857 }
858
859 // remove a ship from the active list
860 void active_list_remove(int ship_class)
861 {
862         ss_active_item *sai, *temp;
863         
864         // next store players not assigned to wings
865         sai = GET_FIRST(&SS_active_head);
866
867         while(sai != END_OF_LIST(&SS_active_head)){
868                 temp = GET_NEXT(sai);
869                 if ( sai->ship_class == ship_class ) {
870                         list_remove(&SS_active_head, sai);
871                         sai->flags = 0;
872                 }
873                 sai = temp;
874         }
875 }
876         
877 // Build up the ship selection active list, which is a list of all ships that the player
878 // can choose from.
879 void init_active_list()
880 {
881         int i;
882         ss_active_item  *sai;
883
884         clear_active_list();
885
886         // build the active list
887         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
888                 if ( Ss_pool[i] > 0 ) {
889                         sai = get_free_active_list_node();
890                         if ( sai != NULL ) {
891                                 sai->ship_class = i;
892                                 list_append(&SS_active_head, sai);
893                                 SS_active_list_size++;
894                         }
895                 }
896         }
897 }
898
899 void ship_select_check_buttons()
900 {
901         int                     i;
902         ss_buttons      *b;
903
904         for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
905                 b = &Ship_select_buttons[gr_screen.res][i];
906                 if ( b->button.pressed() ) {
907                         ship_select_button_do(b->hotspot);
908                 }
909         }
910 }
911
912 // reset the ship selection to the mission defaults
913 void ss_reset_to_default()
914 {
915         if ( Game_mode & GM_MULTIPLAYER ) {
916                 Int3();
917                 return;
918         }
919
920         stop_ship_animation();
921
922         ss_init_pool(&Team_data[Common_team]);
923         ss_init_units();
924         init_active_list();
925         ss_reset_selected_ship();
926         ss_reset_carried_icon();
927
928         // reset weapons 
929         wl_reset_to_defaults();
930
931         start_ship_animation(Selected_ss_class, 1);
932 }
933
934 // -------------------------------------------------------------------
935 // ship_select_redraw_pressed_buttons()
936 //
937 // Redraw any ship select buttons that are pressed down.  This function is needed
938 // since we sometimes need to draw pressed buttons last to ensure the entire
939 // button gets drawn (and not overlapped by other buttons)
940 //
941 void ship_select_redraw_pressed_buttons()
942 {
943         int                     i;
944         ss_buttons      *b;
945         
946         common_redraw_pressed_buttons();
947
948         for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
949                 b = &Ship_select_buttons[gr_screen.res][i];
950                 if ( b->button.pressed() ) {
951                         b->button.draw_forced(2);
952                 }
953         }
954 }
955
956 void ship_select_buttons_init()
957 {
958         ss_buttons      *b;
959         int                     i;
960
961         for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
962                 b = &Ship_select_buttons[gr_screen.res][i];
963                 b->button.create( &Ship_select_ui_window, "", b->x, b->y, 60, 30, b->scrollable);
964                 // set up callback for when a mouse first goes over a button
965                 b->button.set_highlight_action( common_play_highlight_sound );
966                 b->button.set_bmaps(b->filename);
967                 b->button.link_hotspot(b->hotspot);
968         }
969
970         // add all xstrs
971         for(i=0; i<SHIP_SELECT_NUM_TEXT; i++){
972                 Ship_select_ui_window.add_XSTR(&Ship_select_text[gr_screen.res][i]);
973         }
974
975         // We don't want to have the reset button appear in multiplayer
976         if ( Game_mode & GM_MULTIPLAYER ) {
977                 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.disable();
978                 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.hide();
979         }
980
981         Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.disable();
982         Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.hide();
983 }
984
985 // -------------------------------------------------------------------------------------
986 // ship_select_button_do() do the button action for the specified pressed button
987 //
988 void ship_select_button_do(int i)
989 {
990         if ( Background_playing )
991                 return;
992
993         switch ( i ) {
994                 case SHIP_SELECT_SHIP_SCROLL_UP:
995                         if ( Current_screen != ON_SHIP_SELECT )
996                                 break;
997
998                         if ( common_scroll_down_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
999                                 gamesnd_play_iface(SND_SCROLL);
1000                         } else {
1001                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1002                         }
1003                         break;
1004
1005                 case SHIP_SELECT_SHIP_SCROLL_DOWN:
1006                         if ( Current_screen != ON_SHIP_SELECT )
1007                                 break;
1008
1009                         if ( common_scroll_up_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
1010                                 gamesnd_play_iface(SND_SCROLL);
1011                         } else {
1012                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1013                         }
1014
1015                         break;
1016
1017                 case SHIP_SELECT_RESET:
1018                         ss_reset_to_default();
1019                         break;
1020         } // end switch
1021 }
1022
1023 // ---------------------------------------------------------------------
1024 // ship_select_init() is called once when the ship select screen begins
1025 //
1026 //
1027 void ship_select_init()
1028 {
1029         common_set_interface_palette("ShipPalette");
1030         common_flash_button_init();
1031
1032         // if in multiplayer -- set my state to be ship select
1033         if ( Game_mode & GM_MULTIPLAYER ){              
1034                 // also set the ship which is mine as the default
1035                 maybe_change_selected_wing_ship(Net_player->p_info.ship_index/4,Net_player->p_info.ship_index % 4);
1036         }
1037
1038         set_active_ui(&Ship_select_ui_window);
1039         Current_screen = ON_SHIP_SELECT;
1040
1041         Ss_mouse_down_on_region = -1;
1042
1043         help_overlay_set_state(SS_OVERLAY,0);
1044
1045         if ( Ship_select_open ) {
1046                 start_ship_animation( Selected_ss_class );
1047                 common_buttons_maybe_reload(&Ship_select_ui_window);    // AL 11-21-97: this is necessary since we may returning from the hotkey
1048                                                                                                                                                                 // screen, which can release common button bitmaps.
1049                 common_reset_buttons();
1050                 nprintf(("Alan","ship_select_init() returning without doing anything\n"));
1051                 return;
1052         }
1053
1054         nprintf(("Alan","entering ship_select_init()\n"));
1055         common_select_init();
1056
1057         ShipSelectMaskBitmap = bm_load(Ship_select_background_mask_fname[gr_screen.res]);
1058         if (ShipSelectMaskBitmap < 0) {
1059                 if (gr_screen.res == GR_640) {
1060                         Error(LOCATION,"Could not load in 'shipselect-m'!");
1061                 } else if (gr_screen.res == GR_1024) {
1062                         Error(LOCATION,"Could not load in '2_shipselect-m'!");
1063                 }
1064         }
1065
1066         Shipselect_mask_w = -1;
1067         Shipselect_mask_h = -1;
1068
1069         // get a pointer to bitmap by using bm_lock()
1070         ShipSelectMaskPtr = bm_lock(ShipSelectMaskBitmap, 8, BMP_AABITMAP);
1071         ShipSelectMaskData = (ubyte*)ShipSelectMaskPtr->data;   
1072         bm_get_info(ShipSelectMaskBitmap, &Shipselect_mask_w, &Shipselect_mask_h);
1073
1074         help_overlay_load(SS_OVERLAY);
1075
1076         // Set up the mask regions
1077    // initialize the different regions of the menu that will react when the mouse moves over it
1078         Num_mask_regions = 0;
1079         
1080         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_BRIEFING_REGION,                         0);
1081         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_SS_REGION,                                               0);
1082         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_WEAPON_REGION,                           0);
1083         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_COMMIT_REGION,                           0);
1084         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_HELP_REGION,                                     0);
1085         snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_OPTIONS_REGION,                          0);
1086
1087         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_UP,             0);
1088         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_DOWN,           0);
1089
1090         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_0,             0);
1091         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_1,             0);
1092         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_2,             0);
1093         snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_3,             0);
1094
1095         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_0,          0);
1096         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_1,          0);
1097         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_2,          0);
1098         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_3,          0);
1099         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_0,          0);
1100         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_1,          0);
1101         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_2,          0);
1102         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_3,          0);
1103         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_0,          0);
1104         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_1,          0);
1105         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_2,          0);
1106         snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_3,          0);
1107
1108         Ship_select_open = 1;   // This game-wide global flag is set to 1 to indicate that the ship
1109                                                                         // select screen has been opened and memory allocated.  This flag
1110                                                                         // is needed so we can know if ship_select_close() needs to called if
1111                                                                         // restoring a game from the Options screen invoked from ship select
1112
1113         // init ship selection masks and buttons
1114         Ship_select_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1115         Ship_select_ui_window.set_mask_bmap(Ship_select_background_mask_fname[gr_screen.res]);
1116         Ship_select_ui_window.tooltip_handler = ss_tooltip_handler;
1117         common_buttons_init(&Ship_select_ui_window);
1118         ship_select_buttons_init();
1119         start_ship_animation( Selected_ss_class );      
1120
1121         // init ship selection background bitmpa
1122         Ship_select_background_bitmap = bm_load(Ship_select_background_fname[gr_screen.res]);
1123 }
1124
1125
1126 // Return the ship class for the icon specified by index.  Need to iterate through the active
1127 // list of icons to find out what ship class for this icon
1128 //
1129 // input: index => list index (0..3)
1130 // exit:  ship class, -1 if none
1131 //
1132 int ss_get_ship_class_from_list(int index)
1133 {
1134         ss_active_item  *sai;
1135         int                             list_entry, i, count;
1136
1137         i = 0;
1138         count = 0;
1139         list_entry = -1;
1140         for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1141                 count++;
1142                 if ( count <= SS_active_list_start )
1143                         continue;
1144
1145                 if ( i >= MAX_ICONS_ON_SCREEN )
1146                         break;
1147
1148                 if ( i == index ) {
1149                         list_entry = sai->ship_class;
1150                         break;
1151                 }
1152
1153                 i++;
1154         }
1155
1156         return list_entry;
1157 }
1158
1159 // ---------------------------------------------------------------------
1160 // maybe_pick_up_list_icon()
1161 //
1162 void maybe_pick_up_list_icon(int offset)
1163 {
1164         int ship_class;
1165
1166         ship_class = ss_get_ship_class_from_list(offset);
1167         if ( ship_class != -1 ) {
1168                 pick_from_ship_list(offset, ship_class);
1169         }
1170 }
1171
1172 // ---------------------------------------------------------------------
1173 // maybe_change_selected_ship()
1174 //
1175 void maybe_change_selected_ship(int offset)
1176 {
1177         int ship_class;
1178
1179         ship_class = ss_get_ship_class_from_list(offset);
1180         if ( ship_class == -1 )
1181                 return;
1182
1183         if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+offset) ) {
1184                 return;
1185         }
1186
1187         if ( Selected_ss_class == -1 ) {
1188                 Selected_ss_class = ship_class;
1189                 start_ship_animation(Selected_ss_class, 1);
1190         }
1191         else if ( Selected_ss_class != ship_class ) {
1192                 Selected_ss_class = ship_class;
1193                 start_ship_animation(Selected_ss_class, 1);
1194         }
1195         else
1196                 Assert( Selected_ss_class == ship_class );
1197 }
1198
1199 void maybe_change_selected_wing_ship(int wb_num, int ws_num)
1200 {
1201         ss_slot_info    *ss_slot;
1202
1203         Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
1204         Assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS); 
1205         
1206         if ( Ss_wings[wb_num].wingnum < 0 ) {
1207                 return;
1208         }
1209
1210         ss_slot = &Ss_wings[wb_num].ss_slots[ws_num];
1211         switch ( ss_slot->status & ~WING_SLOT_LOCKED ) {
1212
1213                 case WING_SLOT_FILLED:
1214                 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
1215                         if ( Selected_ss_class != -1 && Selected_ss_class != Wss_slots[wb_num*4+ws_num].ship_class ) {
1216                                 Selected_ss_class = Wss_slots[wb_num*4+ws_num].ship_class;
1217                                 start_ship_animation(Selected_ss_class, 1);
1218                         }
1219                         break;
1220
1221                 default:
1222                         // do nothing
1223                         break;
1224         } // end switch
1225 }
1226
1227 // ---------------------------------------------------------------------
1228 // do_mouse_over_wing_slot()
1229 //
1230 // returns:     0 => icon wasn't dropped onto slot
1231 //                              1 => icon was dropped onto slot
1232 int do_mouse_over_wing_slot(int block, int slot)
1233 {
1234         Hot_ss_slot = block*4 + slot;
1235
1236         if ( !mouse_down(MOUSE_LEFT_BUTTON) ) {
1237                 if ( ss_icon_being_carried() ) {
1238
1239                         if ( ss_disabled_slot(block*4+slot) ) {
1240                                 gamesnd_play_iface(SND_ICON_DROP);
1241                                 return 0;
1242                         }
1243
1244                         if ( !ss_carried_icon_moved() ) {
1245                                 ss_reset_carried_icon();
1246                                 return 0;
1247                         }
1248
1249                         ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, Hot_ss_slot, -1);
1250                         ss_reset_carried_icon();
1251                 }
1252         }
1253         else {
1254                 if ( Ss_mouse_down_on_region == (WING_0_SHIP_0+block*4+slot) ) {
1255                         pick_from_wing(block, slot);
1256                 }
1257         }
1258
1259         return 1;
1260 }
1261
1262 void do_mouse_over_list_slot(int index)
1263 {
1264         Hot_ss_icon = index;
1265
1266         if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+index) ){
1267                 return;
1268         }
1269
1270         if ( mouse_down(MOUSE_LEFT_BUTTON) )
1271                 maybe_pick_up_list_icon(index);
1272 }
1273
1274 // Icon has been dropped, but not onto a wing slot
1275 void ss_maybe_drop_icon()
1276 {
1277         if ( Drop_icon_mflag )  {
1278                 if ( ss_icon_being_carried() ) {
1279                         // Add back into the ship entry list
1280                         if ( Carried_ss_icon.from_slot >= 0 ) {
1281                                 // return to list
1282                                 ss_drop(Carried_ss_icon.from_slot, -1, -1, Carried_ss_icon.ship_class);
1283                         } else {
1284                                 if ( ss_carried_icon_moved() ) {
1285                                         gamesnd_play_iface(SND_ICON_DROP);
1286                                 }
1287                         }
1288                         ss_reset_carried_icon();
1289                 }       
1290         }
1291 }
1292
1293 void ss_anim_pause()
1294 {
1295         if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1296                 anim_pause(Ss_icons[Selected_ss_class].anim_instance);
1297         }
1298 }
1299
1300 void ss_anim_unpause()
1301 {
1302         if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1303                 anim_unpause(Ss_icons[Selected_ss_class].anim_instance);
1304         }
1305 }
1306
1307 // maybe flash a button if player hasn't done anything for a while
1308 void ss_maybe_flash_button()
1309 {
1310         if ( common_flash_bright() ) {
1311                 // weapon loadout button
1312                 if ( Common_buttons[Current_screen-1][gr_screen.res][2].button.button_hilighted() ) {
1313                         common_flash_button_init();
1314                 } else {
1315                         Common_buttons[Current_screen-1][gr_screen.res][2].button.draw_forced(1);
1316                 }
1317         }
1318 }
1319
1320
1321 // -------------------------------------------------------------------------------------
1322 // ship_select_render(float frametime)
1323 //
1324 void ship_select_render(float frametime)
1325 {
1326         if ( !Background_playing ) {
1327                 gr_set_bitmap(Ship_select_background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1328                 gr_bitmap(0, 0);
1329         }
1330
1331         anim_render_all(0, frametime);
1332         anim_render_all(ON_SHIP_SELECT, frametime);
1333 }
1334
1335
1336 // blit any active ship information text
1337 void ship_select_blit_ship_info()
1338 {
1339 #ifndef MAKE_FS1
1340         int y_start;
1341         ship_info *sip;
1342         char str[100];
1343         color *header = &Color_white;
1344         color *text = &Color_green;
1345
1346
1347         // if we don't have a valid ship selected, do nothing
1348         if(Selected_ss_class == -1){
1349                 return;
1350         }
1351
1352         // get the ship class
1353         sip = &Ship_info[Selected_ss_class];
1354
1355         // starting line
1356         y_start = Ship_info_coords[gr_screen.res][SHIP_SELECT_Y_COORD];
1357
1358         memset(str,0,100);
1359
1360         // blit the ship class (name)
1361         gr_set_color_fast(header);
1362         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Class",739));
1363         y_start += 10;
1364         if(strlen(sip->name)){
1365                 gr_set_color_fast(text);
1366                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->name);
1367         }
1368         y_start += 10;
1369
1370         // blit the ship type
1371         gr_set_color_fast(header);
1372         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Type",740));
1373         y_start += 10;
1374         if((sip->type_str != NULL) && strlen(sip->type_str)){
1375                 gr_set_color_fast(text);
1376                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->type_str);
1377         }
1378         y_start+=10;
1379
1380         // blit the ship length
1381         gr_set_color_fast(header);
1382         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Length",741));
1383         y_start += 10;
1384         if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1385                 if (Lcl_gr) {
1386                         // in german, drop the s from Meters and make sure M is caps
1387                         char *sp = strstr(sip->ship_length, "Meters");
1388                         if (sp) {
1389                                 sp[5] = ' ';            // make the old s a space now
1390                         }
1391                 }
1392                 gr_set_color_fast(text);
1393                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start, sip->ship_length);
1394         }
1395         y_start += 10;
1396
1397         // blit the max velocity
1398         gr_set_color_fast(header);
1399         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Max Velocity",742));      
1400         y_start += 10;
1401         sprintf(str,XSTR("%d m/s",743),(int)sip->max_vel.xyz.z);
1402         gr_set_color_fast(text);
1403         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,str);
1404         y_start += 10;
1405
1406         // blit the maneuverability
1407         gr_set_color_fast(header);
1408         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Maneuverability",744));
1409         y_start += 10;
1410         if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1411                 gr_set_color_fast(text);
1412                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->maneuverability_str);
1413         }
1414         y_start += 10;
1415
1416         // blit the armor
1417         gr_set_color_fast(header);
1418         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Armor",745));
1419         y_start += 10;
1420         if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1421                 gr_set_color_fast(text);
1422                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->armor_str);
1423         }
1424         y_start += 10;
1425
1426         // blit the gun mounts 
1427         gr_set_color_fast(header);
1428         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Gun Mounts",746));
1429         y_start += 10;
1430         if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1431                 gr_set_color_fast(text);
1432                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->gun_mounts);
1433         }
1434         y_start += 10;
1435
1436         // blit the missile banke
1437         gr_set_color_fast(header);
1438         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Missile Banks",747));
1439         y_start += 10;
1440         if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1441                 gr_set_color_fast(text);
1442                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->missile_banks);
1443         }
1444         y_start += 10;
1445
1446         // blit the manufacturer
1447         gr_set_color_fast(header);
1448         gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Manufacturer",748));
1449         y_start += 10;
1450         if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1451                 gr_set_color_fast(text);
1452                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->manufacturer_str);
1453         }
1454         y_start += 10;
1455
1456         // blit the _short_ text description
1457         /*
1458         Assert(Multi_ts_ship_info_line_count < 3);
1459         gr_set_color_fast(&Color_normal);
1460         for(idx=0;idx<SHIP_SELECT_ship_info_line_count;idx++){
1461                 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start, SHIP_SELECT_ship_info_lines[idx]);
1462                 y_start += 10;
1463         }
1464         */
1465 #endif
1466 }
1467
1468
1469 // ---------------------------------------------------------------------
1470 // ship_select_do() is called once per game frame, and is responsible for
1471 // updating the ship select screen
1472 //
1473 //      frametime is in seconds
1474 void ship_select_do(float frametime)
1475 {
1476         int k, ship_select_choice, snazzy_action;
1477
1478         ship_select_choice = snazzy_menu_do(ShipSelectMaskData, Shipselect_mask_w, Shipselect_mask_h, Num_mask_regions, Region, &snazzy_action, 0);
1479
1480         Hot_ss_icon = -1;
1481         Hot_ss_slot = -1;
1482
1483         k = common_select_do(frametime);
1484
1485         if ( help_overlay_active(SS_OVERLAY) ) {
1486                 ss_anim_pause();
1487         }
1488         else {
1489                 ss_anim_unpause();
1490         }
1491
1492         // Check common keypresses
1493         common_check_keys(k);
1494
1495         if ( Mouse_down_last_frame ) {
1496                 Ss_mouse_down_on_region = ship_select_choice;
1497         }
1498
1499         // Check for the mouse over a region (not clicked, just over)
1500         if ( ship_select_choice > -1 ) {
1501
1502                 switch(ship_select_choice) {
1503                         case SHIP_SELECT_ICON_0:
1504                                 do_mouse_over_list_slot(0);
1505                                 break;
1506                         case SHIP_SELECT_ICON_1:
1507                                 do_mouse_over_list_slot(1);
1508                                 break;
1509                         case SHIP_SELECT_ICON_2:
1510                                 do_mouse_over_list_slot(2);
1511                                 break;
1512                         case SHIP_SELECT_ICON_3:
1513                                 do_mouse_over_list_slot(3);
1514                                 break;
1515                         case WING_0_SHIP_0:
1516                                 if ( do_mouse_over_wing_slot(0,0) )
1517                                         ship_select_choice = -1;
1518                                 break;
1519                         case WING_0_SHIP_1:
1520                                 if ( do_mouse_over_wing_slot(0,1) )
1521                                         ship_select_choice = -1;
1522                                 break;
1523                         case WING_0_SHIP_2:
1524                                 if ( do_mouse_over_wing_slot(0,2) )
1525                                         ship_select_choice = -1;
1526                                 break;
1527                         case WING_0_SHIP_3:
1528                                 if ( do_mouse_over_wing_slot(0,3) )
1529                                         ship_select_choice = -1;
1530                                 break;
1531                         case WING_1_SHIP_0:
1532                                 if ( do_mouse_over_wing_slot(1,0) )
1533                                         ship_select_choice = -1;
1534                                 break;
1535                         case WING_1_SHIP_1:
1536                                 if ( do_mouse_over_wing_slot(1,1) )
1537                                         ship_select_choice = -1;
1538                                 break;
1539                         case WING_1_SHIP_2:
1540                                 if ( do_mouse_over_wing_slot(1,2) )
1541                                         ship_select_choice = -1;
1542                                 break;
1543                         case WING_1_SHIP_3:
1544                                 if ( do_mouse_over_wing_slot(1,3) )
1545                                         ship_select_choice = -1;
1546                                 break;
1547                         case WING_2_SHIP_0:
1548                                 if ( do_mouse_over_wing_slot(2,0) )
1549                                         ship_select_choice = -1;
1550                                 break;
1551                         case WING_2_SHIP_1:
1552                                 if ( do_mouse_over_wing_slot(2,1) )
1553                                         ship_select_choice = -1;
1554                                 break;
1555                         case WING_2_SHIP_2:
1556                                 if ( do_mouse_over_wing_slot(2,2) )
1557                                         ship_select_choice = -1;
1558                                 break;
1559                         case WING_2_SHIP_3:
1560                                 if ( do_mouse_over_wing_slot(2,3) )
1561                                         ship_select_choice = -1;
1562                                 break;
1563
1564                         default:
1565                                 break;
1566                 }       // end switch
1567         }
1568
1569         // check buttons
1570         common_check_buttons();
1571         ship_select_check_buttons();
1572
1573         // Check for the mouse clicks over a region
1574         if ( ship_select_choice > -1 && snazzy_action == SNAZZY_CLICKED ) {
1575                 switch (ship_select_choice) {
1576
1577                         case SHIP_SELECT_ICON_0:
1578                                 maybe_change_selected_ship(0);
1579                                 break;
1580
1581                         case SHIP_SELECT_ICON_1:
1582                                 maybe_change_selected_ship(1);
1583                                 break;
1584
1585                         case SHIP_SELECT_ICON_2:
1586                                 maybe_change_selected_ship(2);
1587                                 break;
1588
1589                         case SHIP_SELECT_ICON_3:
1590                                 maybe_change_selected_ship(3);
1591                                 break;
1592
1593                         case WING_0_SHIP_0:
1594                                 maybe_change_selected_wing_ship(0,0);
1595                                 break;
1596
1597                         case WING_0_SHIP_1:
1598                                 maybe_change_selected_wing_ship(0,1);
1599                                 break;
1600
1601                         case WING_0_SHIP_2:
1602                                 maybe_change_selected_wing_ship(0,2);
1603                                 break;
1604
1605                         case WING_0_SHIP_3:
1606                                 maybe_change_selected_wing_ship(0,3);
1607                                 break;
1608
1609                         case WING_1_SHIP_0:
1610                                 maybe_change_selected_wing_ship(1,0);
1611                                 break;
1612
1613                         case WING_1_SHIP_1:
1614                                 maybe_change_selected_wing_ship(1,1);
1615                                 break;
1616
1617                         case WING_1_SHIP_2:
1618                                 maybe_change_selected_wing_ship(1,2);
1619                                 break;
1620
1621                         case WING_1_SHIP_3:
1622                                 maybe_change_selected_wing_ship(1,3);
1623                                 break;
1624
1625                         case WING_2_SHIP_0:
1626                                 maybe_change_selected_wing_ship(2,0);
1627                                 break;
1628
1629                         case WING_2_SHIP_1:
1630                                 maybe_change_selected_wing_ship(2,1);
1631                                 break;
1632
1633                         case WING_2_SHIP_2:
1634                                 maybe_change_selected_wing_ship(2,2);
1635                                 break;
1636
1637                         case WING_2_SHIP_3:
1638                                 maybe_change_selected_wing_ship(2,3);
1639                                 break;
1640
1641                         default:
1642                                 break;
1643
1644                 }       // end switch
1645         }
1646
1647         ss_maybe_drop_icon();
1648
1649         if ( Ship_anim_class >= 0) {
1650                 Assert(Selected_ss_class >= 0);
1651                 if ( Ss_icons[Selected_ss_class].anim_instance->frame_num == Ss_icons[Selected_ss_class].anim_instance->stop_at ) { 
1652                         nprintf(("anim", "Frame number = %d, Stop at %d\n", Ss_icons[Selected_ss_class].anim_instance->frame_num, Ss_icons[Selected_ss_class].anim_instance->stop_at));
1653                         anim_play_struct aps;
1654                         anim_release_render_instance(Ss_icons[Selected_ss_class].anim_instance);
1655                         anim_play_init(&aps, Ss_icons[Selected_ss_class].anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1656                         aps.start_at = SHIP_ANIM_LOOP_FRAME;
1657 //                      aps.start_at = 0;
1658                         aps.screen_id = ON_SHIP_SELECT;
1659                         aps.framerate_independent = 1;
1660                         aps.skip_frames = 0;
1661                         Ss_icons[Selected_ss_class].anim_instance = anim_play(&aps);
1662                 }
1663         }
1664
1665         gr_reset_clip();
1666
1667         ship_select_render(frametime);
1668         if ( !Background_playing ) {            
1669                 Ship_select_ui_window.draw();
1670                 ship_select_redraw_pressed_buttons();
1671                 common_render_selected_screen_button();
1672         }
1673
1674         // The background transition plays once. Display ship icons after Background done playing
1675         if ( !Background_playing ) {
1676                 draw_ship_icons();
1677                 for ( int i = 0; i < MAX_WING_BLOCKS; i++ ) {
1678                         draw_wing_block(i, Hot_ss_slot, -1, Selected_ss_class);
1679                 }               
1680         }
1681         
1682         if ( ss_icon_being_carried() ) {
1683                 int mouse_x, mouse_y;
1684                 mouse_get_pos( &mouse_x, &mouse_y );
1685                 gr_set_bitmap(Ss_icons[Carried_ss_icon.ship_class].icon_bmaps[ICON_FRAME_SELECTED], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1686                 gr_bitmap(mouse_x + Ss_delta_x , mouse_y + Ss_delta_y);
1687         }
1688
1689         // draw out ship information
1690         ship_select_blit_ship_info();
1691
1692
1693         ss_maybe_flash_button();
1694
1695         // blit help overlay if active
1696         help_overlay_maybe_blit(SS_OVERLAY);
1697
1698         // If the commit button was pressed, do the commit button actions.  Done at the end of the
1699         // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1700         // the ship model is not in memory
1701         if ( Commit_pressed ) {         
1702                 commit_pressed();               
1703                 Commit_pressed = 0;
1704         }
1705
1706         gr_flip();
1707
1708         if ( Game_mode & GM_MULTIPLAYER ) {
1709                 if ( Selected_ss_class >= 0 )
1710                         Net_player->p_info.ship_class = Selected_ss_class;
1711         }        
1712
1713         if(!Background_playing){
1714                 // should render this as close to last as possible so it overlaps all controls
1715                 // chatbox_render();            
1716         }
1717
1718         // If the commit button was pressed, do the commit button actions.  Done at the end of the
1719         // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1720         // the ship model is not in memory
1721         if ( Commit_pressed ) {         
1722                 commit_pressed();               
1723                 Commit_pressed = 0;
1724         }
1725 }
1726
1727
1728 // ------------------------------------------------------------------------
1729 //      ship_select_close() is called once when the ship select screen is exited
1730 //
1731 //
1732 void ship_select_close()
1733 {
1734         key_flush();
1735
1736         if ( !Ship_select_open ) {
1737                 nprintf(("Alan","ship_select_close() returning without doing anything\n"));
1738                 return;
1739         }
1740
1741         nprintf(("Alan", "Entering ship_select_close()\n"));
1742
1743         // done with the bitmaps, so unlock it
1744         bm_unlock(ShipSelectMaskBitmap);
1745
1746         // unload the bitmaps
1747         bm_unload(ShipSelectMaskBitmap);
1748         help_overlay_unload(SS_OVERLAY);
1749
1750         // release the bitmpas that were previously extracted from anim files
1751         ss_unload_icons();
1752
1753         // Release any active ship anim instances
1754         unload_ship_anim_instances();
1755
1756         // unload ship animations if they were loaded
1757         unload_ship_anims();
1758
1759         Ship_select_ui_window.destroy();
1760
1761 #ifdef MAKE_FS1
1762         common_free_interface_palette();
1763 #endif
1764
1765         Ship_anim_class = -1;
1766         Ship_select_open = 0;   // This game-wide global flag is set to 0 to indicate that the ship
1767                                                                         // select screen has been closed and memory freed.  This flag
1768                                                                         // is needed so we can know if ship_select_close() needs to called if
1769                                                                         // restoring a game from the Options screen invoked from ship select
1770 }
1771
1772 //      ss_unload_icons() frees the bitmaps used for ship icons 
1773 void ss_unload_icons()
1774 {
1775         int                                     i,j;
1776         ss_icon_info            *icon;
1777
1778         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1779                 icon = &Ss_icons[i];
1780
1781                 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
1782                         if ( icon->icon_bmaps[j] >= 0 ) {
1783                                 bm_release(icon->icon_bmaps[j]);
1784                                 icon->icon_bmaps[j] = -1;
1785                         }
1786                 }
1787         }
1788 }
1789
1790 // ------------------------------------------------------------------------
1791 //      draw_ship_icons() will request which icons to draw on screen.
1792 void draw_ship_icons()
1793 {
1794         int i;
1795         int count=0;
1796
1797         ss_active_item  *sai;
1798         i = 0;
1799         for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1800                 count++;
1801                 if ( count <= SS_active_list_start )
1802                         continue;
1803
1804                 if ( i >= MAX_ICONS_ON_SCREEN )
1805                         break;
1806
1807                 draw_ship_icon_with_number(i, sai->ship_class);
1808                 i++;
1809         }
1810 }
1811
1812 // ------------------------------------------------------------------------
1813 //      draw_ship_icon_with_number() will draw a ship icon on screen with the
1814 // number of available ships to the left.
1815 //
1816 //
1817 void draw_ship_icon_with_number(int screen_offset, int ship_class)
1818 {
1819         char    buf[32];
1820         int     num_x,num_y;
1821         ss_icon_info *ss_icon;
1822
1823
1824         Assert( screen_offset >= 0 && screen_offset <= 3 );
1825         Assert( ship_class >= 0 );
1826         ss_icon = &Ss_icons[ship_class];
1827
1828         num_x = Ship_list_coords[gr_screen.res][screen_offset][2];
1829         num_y = Ship_list_coords[gr_screen.res][screen_offset][3];
1830         
1831         // assume default bitmap is to be used
1832         ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_NORMAL];
1833
1834         // next check if ship has mouse over it
1835         if ( Hot_ss_icon > -1 ) {
1836                 Assert(Hot_ss_icon <= 3);
1837                 if ( Hot_ss_icon == screen_offset )
1838                         ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_HOT];
1839         }
1840
1841         // highest precedence is if the ship is selected
1842         if ( Selected_ss_class > -1 ) {
1843                 if ( Selected_ss_class == ship_class )
1844                         ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_SELECTED];
1845         }
1846
1847         if ( Ss_pool[ship_class] <= 0 ) {
1848                 return;
1849         }
1850
1851         // blit the icon
1852         gr_set_bitmap(ss_icon->current_icon_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1853         gr_bitmap(Ship_list_coords[gr_screen.res][screen_offset][0], Ship_list_coords[gr_screen.res][screen_offset][1]);
1854
1855         // blit the number
1856         sprintf(buf, "%d", Ss_pool[ship_class] );
1857         gr_set_color_fast(&Color_white);
1858         gr_string(num_x, num_y, buf);
1859 }
1860
1861 // ------------------------------------------------------------------------
1862 //      stop_ship_animation() will halt the currently playing ship animation.  The
1863 // instance will be freed, (but the compressed data is not freed).  The animation
1864 // will not display after this function is called (even on this frame), since
1865 // the instance is removed from the anim_render_list.
1866 void stop_ship_animation()
1867 {
1868         ss_icon_info    *ss_icon;
1869
1870         if ( Ship_anim_class == -1 ) 
1871                 return;
1872
1873         ss_icon = &Ss_icons[Ship_anim_class];
1874
1875         anim_release_render_instance(ss_icon->anim_instance);
1876         ss_icon->anim_instance = NULL;
1877
1878         Ship_anim_class = -1;
1879 }
1880
1881
1882 // ------------------------------------------------------------------------
1883 // this loads an individual animation file
1884 // it attempts to load a hires version (ie, it attaches a "2_" in front of the
1885 // filename. if no hires version is available, it defaults to the lowres
1886
1887 anim* ss_load_individual_animation(int ship_class)
1888 {
1889         anim *p_anim;
1890         char animation_filename[CF_MAX_FILENAME_LENGTH+4];
1891         
1892         // 1024x768 SUPPORT
1893         // If we are in 1024x768, we first want to append "2_" in front of the filename
1894         if (gr_screen.res == GR_1024) {
1895                 Assert(strlen(Ship_info[ship_class].anim_filename) <= 30);
1896                 strcpy(animation_filename, "2_");
1897                 strcat(animation_filename, Ship_info[ship_class].anim_filename);
1898                 // now check if file exists
1899                 // GRR must add a .ANI at the end for detection
1900                 strcat(animation_filename, ".ani");
1901                 
1902                 p_anim = anim_load(animation_filename, 1);
1903                 if (p_anim == NULL) {
1904                         // failed loading hi-res, revert to low res
1905                         strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1906                         p_anim = anim_load(animation_filename, 1);
1907                         mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename)); 
1908                 } else {
1909                         mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1910                 }
1911                 /*
1912                 // this is lame and doesnt work cuz cf_exist() doesnt search the packfiles
1913                 if (!cf_exist(animation_filename, CF_TYPE_INTERFACE)) {
1914                         // file does not exist, use original low res version
1915                         strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1916                         mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename)); 
1917                 } else {
1918                         animation_filename[strlen(animation_filename) - 4] = '\0';
1919                         mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1920                 }
1921                 */
1922         } else {
1923                 strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1924                 p_anim = anim_load(animation_filename, 1);
1925         }
1926         
1927         return p_anim;
1928 }
1929
1930 // ------------------------------------------------------------------------
1931 //      start_ship_animation() will start a ship animation playing, and will 
1932 // load the compressed anim from disk if required.
1933 void start_ship_animation(int ship_class, int play_sound)
1934 {
1935         ss_icon_info    *ss_icon;
1936         Assert( ship_class >= 0 );
1937
1938         if ( Ship_anim_class == ship_class ) 
1939                 return;
1940
1941         if ( Ship_anim_class >= 0 ) {
1942                 stop_ship_animation();
1943         }
1944
1945         ss_icon = &Ss_icons[ship_class];
1946
1947         // see if we need to load in the animation from disk
1948         if ( ss_icon->anim == NULL ) {
1949                 ss_icon->anim = ss_load_individual_animation(ship_class);
1950         }
1951
1952         // see if we need to get an instance
1953         if ( ss_icon->anim_instance == NULL ) {
1954                 anim_play_struct aps;
1955
1956                 anim_play_init(&aps, ss_icon->anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1957                 aps.screen_id = ON_SHIP_SELECT;
1958                 aps.framerate_independent = 1;
1959                 aps.skip_frames = 0;
1960                 ss_icon->anim_instance = anim_play(&aps);
1961         }
1962
1963         Ship_anim_class = ship_class;
1964
1965 //      if ( play_sound ) {
1966                 gamesnd_play_iface(SND_SHIP_ICON_CHANGE);
1967 //      }
1968 }
1969
1970 // ------------------------------------------------------------------------
1971 //      unload_ship_anims() will free all compressed anims from memory that were
1972 // loaded for the ship animations.
1973 //
1974 //
1975 void unload_ship_anims()
1976 {
1977         for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1978                 if ( Ss_icons[i].anim ) {
1979                         anim_free(Ss_icons[i].anim);
1980                         Ss_icons[i].anim = NULL;
1981                 }
1982         }
1983 }
1984
1985 // ------------------------------------------------------------------------
1986 //      unload_ship_anim_instances() will free any active ship animation instances.
1987 //
1988 //
1989 void unload_ship_anim_instances()
1990 {
1991         for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1992                 if ( Ss_icons[i].anim_instance ) {
1993                         anim_release_render_instance(Ss_icons[i].anim_instance);
1994                         Ss_icons[i].anim_instance = NULL;
1995                 }
1996         }
1997 }
1998
1999 // ------------------------------------------------------------------------
2000 // commit_pressed() is called when the commit button from any of the briefing/ship select/ weapon
2001 // select screens is pressed.  The ship selected is created, and the interface music is stopped.
2002 void commit_pressed()
2003 {
2004         int player_ship_info_index;
2005         
2006         if ( Wss_num_wings > 0 ) {
2007                 if(!(Game_mode & GM_MULTIPLAYER)){
2008                         int rc;
2009                         rc = create_wings();
2010                         if (rc != 0) {
2011                                 gamesnd_play_iface(SND_GENERAL_FAIL);
2012                                 return;
2013                         }
2014                 }
2015         }
2016         else {
2017
2018                 if ( Selected_ss_class == -1 ) {
2019                         player_ship_info_index = Team_data[Common_team].default_ship;
2020
2021                 } else {
2022                         Assert(Selected_ss_class >= 0 );
2023                         player_ship_info_index = Selected_ss_class;
2024                 }
2025
2026                 update_player_ship( player_ship_info_index );
2027                 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[0]) == -1 ) {
2028                         popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
2029                         return;
2030                 }
2031         }
2032
2033         // Check to ensure that the hotkeys are still pointing to valid objects.  It is possible
2034         // for the player to assign a ship to a hotkey, then go and delete that ship in the 
2035         // ship selection, and then try to start the mission.  This function will detect those objects,
2036         // and remove them from the hotkey linked lists.
2037         mission_hotkey_validate();
2038
2039         gamesnd_play_iface(SND_COMMIT_PRESSED);
2040
2041         // save the player loadout
2042         if ( !(Game_mode & GM_MULTIPLAYER) ) {
2043                 strcpy(Player_loadout.filename, Game_current_mission_filename);
2044                 strcpy(Player_loadout.last_modified, The_mission.modified);
2045                 wss_save_loadout();
2046         }
2047
2048         // move to the next stage
2049         // in multiplayer this is the final mission sync
2050         if(Game_mode & GM_MULTIPLAYER){         
2051                 Multi_sync_mode = MULTI_SYNC_POST_BRIEFING;
2052                 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);        
2053                 
2054                 // otherwise tell the standalone to move everyone into this state and continue
2055                 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2056                         send_mission_sync_packet(MULTI_SYNC_POST_BRIEFING);
2057                 }
2058         }
2059         // in single player we jump directly into the mission
2060         else {
2061                 gameseq_post_event(GS_EVENT_ENTER_GAME);
2062         }
2063 }
2064
2065 // ------------------------------------------------------------------------
2066 // pick_from_ship_list() will determine if an icon from the ship selection
2067 // list can be picked up (for drag and drop).  It calculates the difference
2068 // in x & y between the icon and the mouse, so we can move the icon with the
2069 // mouse in a realistic way
2070 int pick_from_ship_list(int screen_offset, int ship_class)
2071 {
2072         int rval = -1;
2073         Assert(ship_class >= 0);
2074
2075         if ( Wss_num_wings == 0 )
2076                 return rval;
2077
2078         // If carrying an icon, then do nothing
2079         if ( ss_icon_being_carried() )
2080                 return rval;
2081
2082         if ( Ss_pool[ship_class] > 0 ) {
2083                 int mouse_x, mouse_y;
2084
2085                 ss_set_carried_icon(-1, ship_class);
2086                 mouse_get_pos( &mouse_x, &mouse_y );
2087                 Ss_delta_x = Ship_list_coords[gr_screen.res][screen_offset][0] - mouse_x;
2088                 Ss_delta_y = Ship_list_coords[gr_screen.res][screen_offset][1] - mouse_y;
2089                 Assert( Ss_pool[ship_class] >= 0 );
2090                 rval = 0;
2091         }
2092
2093         common_flash_button_init();
2094         return rval;
2095 }
2096
2097 // ------------------------------------------------------------------------
2098 // pick_from_wing() will determine if an icon from the wing formation (wb_num)
2099 // and slot number (ws_num) can be picked up (for drag and drop).  It calculates
2100 // the difference in x & y between the icon and the mouse, so we can move the icon with the
2101 // mouse in a realistic way
2102 void pick_from_wing(int wb_num, int ws_num)
2103 {
2104         int slot_index;
2105         Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
2106         Assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS);
2107         
2108         ss_wing_info *wb;
2109         ss_slot_info *ws;
2110         wb = &Ss_wings[wb_num];
2111         ws = &wb->ss_slots[ws_num];
2112         slot_index = wb_num*4+ws_num;
2113
2114         if ( wb->wingnum < 0 )
2115                 return;
2116
2117         // Take care of case where the mouse button goes from up to down in one frame while
2118         // carrying an icon
2119         if ( Drop_on_wing_mflag && ss_icon_being_carried() ) {
2120                 if ( !ss_disabled_slot(slot_index) ) {
2121                         ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, slot_index, -1);
2122                         ss_reset_carried_icon();
2123                         gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2124                 }
2125         }
2126
2127         if ( ss_icon_being_carried() )
2128                 return;
2129
2130         if ( ss_disabled_slot(slot_index) ) {
2131                 return;
2132         }
2133
2134         switch ( ws->status ) {
2135                 case WING_SLOT_DISABLED:
2136                 case WING_SLOT_IGNORE:
2137                         return;
2138                         break;
2139
2140                 case WING_SLOT_EMPTY:
2141                 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2142                         // TODO: add fail sound
2143                         return;
2144                         break;
2145
2146                 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2147                 case WING_SLOT_FILLED:
2148                         {
2149                         int mouse_x, mouse_y;
2150                         Assert(Wss_slots[slot_index].ship_class >= 0);
2151                         ss_set_carried_icon(slot_index, Wss_slots[slot_index].ship_class);
2152
2153                         mouse_get_pos( &mouse_x, &mouse_y );
2154                         Ss_delta_x = Wing_icon_coords[gr_screen.res][slot_index][0] - mouse_x;
2155                         Ss_delta_y = Wing_icon_coords[gr_screen.res][slot_index][1] - mouse_y;
2156                         Carried_ss_icon.from_x = mouse_x;
2157                         Carried_ss_icon.from_y = mouse_y;
2158                         }
2159                         break;
2160         
2161                 default:
2162                         Int3();
2163                         break;
2164
2165         } // end switch
2166
2167         common_flash_button_init();
2168 }
2169
2170 // ------------------------------------------------------------------------
2171 // draw_wing_block() will draw the wing icons for the wing formation number
2172 // passed in as a parameter.  
2173 //
2174 // input:       wb_num  =>              wing block number (numbering starts at 0)
2175 //                              hot_slot        =>              index of slot that mouse is over
2176 //                              selected_slot   =>      index of slot that is selected
2177 //                              class_select    =>      all ships of this class are drawn selected (send -1 to not use)
2178 void draw_wing_block(int wb_num, int hot_slot, int selected_slot, int class_select)
2179 {
2180         ss_wing_info    *wb;
2181         ss_slot_info    *ws;
2182         ss_icon_info    *icon;
2183         wing                            *wp;
2184         int                             i, bitmap_to_draw, w, h, sx, sy, slot_index;
2185
2186         Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);                
2187         wb = &Ss_wings[wb_num];
2188         
2189         if ( wb->wingnum == -1 )
2190                 return; 
2191         
2192         // print the wing name under the wing
2193         wp = &Wings[wb->wingnum];
2194         gr_get_string_size(&w, &h, wp->name);
2195         sx = Wing_icon_coords[gr_screen.res][wb_num*4][0] + 16 - w/2;
2196         sy = Wing_icon_coords[gr_screen.res][wb_num*4 + 3][1] + 32 + h;
2197         gr_set_color_fast(&Color_normal);
2198         gr_string(sx, sy, wp->name);
2199
2200         for ( i = 0; i < MAX_WING_SLOTS; i++ ) {
2201                 bitmap_to_draw = -1;
2202                 ws = &wb->ss_slots[i];
2203                 slot_index = wb_num*4 + i;
2204
2205                 if ( Wss_slots[slot_index].ship_class >= 0 ) {
2206                         icon = &Ss_icons[Wss_slots[slot_index].ship_class];
2207                 } else {
2208                         icon = NULL;
2209                 }
2210
2211                 switch(ws->status & ~WING_SLOT_LOCKED ) {
2212                         case WING_SLOT_FILLED:
2213                         case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2214
2215                                 Assert(icon);
2216
2217                                 if ( class_select >= 0 ) {      // only ship select
2218                                         if ( Carried_ss_icon.from_slot == slot_index ) {
2219                                                 if ( ss_carried_icon_moved() ) {
2220                                                         bitmap_to_draw = Wing_slot_empty_bitmap;
2221                                                 } else {
2222                                                         bitmap_to_draw = -1;
2223                                                 }
2224                                                 break;
2225                                         }
2226                                 }
2227
2228                                 if ( ws->status & WING_SLOT_LOCKED ) {                                  
2229                                         bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2230
2231                                         // in multiplayer, determine if this it the special case where the slot is disabled, and 
2232                                         // it is also _my_ slot (ie, team capatains/host have not locked players yet)
2233                                         if((Game_mode & GM_MULTIPLAYER) && multi_ts_disabled_high_slot(slot_index)){
2234                                                 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED_HIGH];
2235                                         }
2236
2237                                         break;
2238                                 }
2239
2240                                 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_NORMAL];
2241                                 if ( selected_slot == slot_index || class_select == Wss_slots[slot_index].ship_class) {
2242                                         bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2243                                 } else if ( hot_slot == slot_index ) {
2244                                         if ( mouse_down(MOUSE_LEFT_BUTTON) ){
2245                                                 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2246                                         } else {
2247                                                 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_HOT];
2248                                         }
2249                                 }
2250
2251                                 if ( ws->status & WING_SLOT_IS_PLAYER && (selected_slot != slot_index) ) {
2252                                         bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_PLAYER];
2253                                 }
2254                                 break;
2255
2256                         case WING_SLOT_EMPTY:
2257                         case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2258                                 bitmap_to_draw = Wing_slot_empty_bitmap;
2259                                 break;
2260
2261                         case WING_SLOT_DISABLED:
2262                         case WING_SLOT_IGNORE:
2263                                 if ( icon ) {
2264                                         bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2265                                 } else {
2266                                         bitmap_to_draw = Wing_slot_disabled_bitmap;
2267                                 }
2268                                 break;
2269
2270                         default:
2271                                 Int3();
2272                                 break;
2273
2274                 }       // end switch
2275
2276                 
2277                 if ( bitmap_to_draw != -1 ) {
2278                         gr_set_bitmap(bitmap_to_draw, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2279                         gr_bitmap(Wing_icon_coords[gr_screen.res][slot_index][0], Wing_icon_coords[gr_screen.res][slot_index][1]);
2280                 }
2281         }
2282 }
2283
2284 // called by multiplayer team select to set the slot based flags
2285 void ss_make_slot_empty(int slot_index)
2286 {
2287         int wing_num,slot_num;
2288         ss_wing_info    *wb;
2289         ss_slot_info    *ws;
2290
2291         // calculate the wing #
2292         wing_num = slot_index / 4;
2293         slot_num = slot_index % 4;
2294
2295         // get the wing and slot entries
2296         wb = &Ss_wings[wing_num];
2297         ws = &wb->ss_slots[slot_num];
2298
2299         // set the flags
2300         ws->status &= ~(WING_SLOT_FILLED | WING_SLOT_DISABLED);
2301         ws->status |= WING_SLOT_EMPTY;
2302 }
2303
2304 // called by multiplayer team select to set the slot based flags
2305 void ss_make_slot_full(int slot_index)
2306 {
2307         int wing_num,slot_num;
2308         ss_wing_info    *wb;
2309         ss_slot_info    *ws;
2310
2311         // calculate the wing #
2312         wing_num = slot_index / 4;
2313         slot_num = slot_index % 4;
2314
2315         // get the wing and slot entries
2316         wb = &Ss_wings[wing_num];
2317         ws = &wb->ss_slots[slot_num];
2318
2319         // set the flags
2320         ws->status &= ~(WING_SLOT_EMPTY | WING_SLOT_DISABLED);
2321         ws->status |= WING_SLOT_FILLED;
2322 }
2323
2324 void ss_blit_ship_icon(int x,int y,int ship_class,int bmap_num)
2325 {
2326         // blit the bitmap in the correct location
2327         if(ship_class == -1){
2328                 gr_set_bitmap(Wing_slot_empty_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2329         } else {
2330                 ss_icon_info *icon = &Ss_icons[ship_class];
2331                 Assert(icon->icon_bmaps[bmap_num] != -1);       
2332                 gr_set_bitmap(icon->icon_bmaps[bmap_num], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2333         }
2334         gr_bitmap(x,y); 
2335 }
2336
2337 // ------------------------------------------------------------------------
2338 //      unload_ship_icons() frees the memory that was used to hold the bitmaps
2339 // for ship icons 
2340 //
2341 void unload_wing_icons()
2342 {
2343         if ( Wing_slot_empty_bitmap != -1 ) {
2344                 bm_release(Wing_slot_empty_bitmap);
2345                 Wing_slot_empty_bitmap = -1;
2346         }
2347
2348         if ( Wing_slot_disabled_bitmap != -1 ) {
2349                 bm_release(Wing_slot_disabled_bitmap);
2350                 Wing_slot_disabled_bitmap = -1;
2351         }
2352 }
2353
2354 // ------------------------------------------------------------------------
2355 //      create_wings() will ensure the correct ships are in the player wings
2356 // for the game.  It works by calling change_ship_type() on the wing ships
2357 // so they match what the player selected.   ship_create() is called for the
2358 // player ship (and current_count, ship_index[] is updated), since it is not yet
2359 // part of the wing structure.
2360 //
2361 // returns:   0 ==> success
2362 //           !0 ==> failure
2363 int create_wings()
2364 {
2365         ss_wing_info            *wb;
2366         ss_slot_info            *ws;
2367         wing                                    *wp;
2368         p_object                                *p_objp;
2369
2370         int shipnum, objnum, slot_index;
2371         int cleanup_ship_index[MAX_WING_SLOTS];
2372         int i,j,k;
2373         int found_pobj;
2374
2375         for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2376                 
2377                 wb = &Ss_wings[i];
2378
2379                 if ( wb->wingnum ==  -1 )
2380                         continue;
2381
2382                 wp = &Wings[wb->wingnum];               
2383                 
2384                 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2385                         slot_index = i*4+j;
2386                         ws = &wb->ss_slots[j];
2387                         switch ( ws->status ) {
2388
2389                                 case WING_SLOT_FILLED:
2390                                 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2391                                 case WING_SLOT_FILLED|WING_SLOT_LOCKED:
2392                                 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER|WING_SLOT_LOCKED:
2393                                         if ( wp->ship_index[j] >= 0 ) {
2394                                                 Assert(Ships[wp->ship_index[j]].objnum >= 0);
2395                                         }
2396
2397                                         if ( ws->status & WING_SLOT_IS_PLAYER ) {
2398                                                 update_player_ship(Wss_slots[slot_index].ship_class);
2399
2400                                                 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[i*4+j]) == -1 ) {
2401                                                         popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
2402                                                         return -1;
2403                                                 }
2404
2405                                                 objnum = OBJ_INDEX(Player_obj);
2406                                                 shipnum = Objects[objnum].instance;
2407                                         } else {
2408                                                 if ( wb->is_late) {
2409                                                         found_pobj = 0;
2410                                                         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2411                                                                 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2412                                                                         if ( ws->sa_index == (p_objp-ship_arrivals) ) {
2413                                                                                 p_objp->ship_class = Wss_slots[slot_index].ship_class;
2414                                                                                 wl_update_parse_object_weapons(p_objp, &Wss_slots[i*4+j]);
2415                                                                                 found_pobj = 1;
2416                                                                                 break;
2417                                                                         }
2418                                                                 }
2419                                                         }
2420                                                         Assert(found_pobj);
2421                                                 }
2422                                                 else {
2423                                                         // AL 10/04/97
2424                                                         // Change the ship type of the ship if different than current.
2425                                                         // NOTE: This will reset the weapons for this ship.  I think this is
2426                                                         //       the right thing to do, since the ships may have different numbers
2427                                                         //                      of weapons and may not have the same allowed weapon types
2428                                                         if ( Ships[wp->ship_index[j]].ship_info_index != Wss_slots[slot_index].ship_class )
2429                                                                 change_ship_type(wp->ship_index[j], Wss_slots[slot_index].ship_class);
2430                                                         wl_update_ship_weapons(Ships[wp->ship_index[j]].objnum, &Wss_slots[i*4+j]);
2431                                                 }
2432                                         }
2433
2434                                         break;
2435
2436                                 case WING_SLOT_EMPTY:
2437                                 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2438                                         if ( ws->status & WING_SLOT_IS_PLAYER ) {                                               
2439                                                 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player %s must select a place in player wing", 462), Player->callsign);
2440                                                 return -1;
2441                                         }
2442                                         break;
2443
2444                                 default:
2445                                         break;
2446                         }
2447                 }       // end for (wing slot)  
2448         }       // end for (wing block)
2449
2450         for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2451                 wb = &Ss_wings[i];
2452                 wp = &Wings[wb->wingnum];               
2453
2454                 if ( wb->wingnum == -1 )
2455                         continue;
2456
2457                 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2458                         cleanup_ship_index[k] = -1;
2459                 }
2460
2461                 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2462                         ws = &wb->ss_slots[j];
2463                         switch( ws->status ) {
2464                                 case WING_SLOT_EMPTY:   
2465                                         // delete ship that is not going to be used by the wing
2466                                         if ( wb->is_late ) {
2467                                                 list_remove( &ship_arrival_list, &ship_arrivals[ws->sa_index]);
2468                                                 wp->wave_count--;
2469                                                 Assert(wp->wave_count >= 0);
2470                                         }
2471                                         else {
2472                                                 shipnum = wp->ship_index[j];
2473                                                 Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
2474                                                 cleanup_ship_index[j] = shipnum;
2475                                                 ship_add_exited_ship( &Ships[shipnum], SEF_PLAYER_DELETED );
2476                                                 obj_delete(Ships[shipnum].objnum);
2477                                                 hud_set_wingman_status_none( Ships[shipnum].wing_status_wing_index, Ships[shipnum].wing_status_wing_pos);
2478                                         }
2479                                         break;
2480
2481                                 default:
2482                                         break;
2483
2484                         } // end switch
2485
2486                 }       // end for (wing slot)  
2487
2488                 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2489                         if ( cleanup_ship_index[k] != -1 ) {
2490                                 ship_wing_cleanup( cleanup_ship_index[k], wp );
2491                         }
2492                 }
2493
2494         }       // end for (wing block)
2495         
2496         return 0;
2497 }
2498
2499 void ship_stop_animation()
2500 {
2501         if ( Ship_anim_class >= 0  )
2502                 stop_ship_animation();
2503 }
2504
2505 // ----------------------------------------------------------------------------
2506 // update_player_ship()
2507 //
2508 // Updates the ship class of the player ship
2509 //
2510 //      parameters:     si_index  => ship info index of ship class to change to
2511 //
2512 //
2513 void update_player_ship(int si_index)
2514 {
2515         Assert( si_index >= 0 );
2516         Assert( Player_obj != NULL);
2517
2518         // AL 10/04/97
2519         // Change the ship type of the player ship if different than current.
2520         // NOTE: This will reset the weapons for this ship.  I think this is
2521         //       the right thing to do, since the ships may have different numbers
2522         //                      of weapons and may not have the same allowed weapon types
2523         if ( Player_ship->ship_info_index != si_index ) 
2524                 change_ship_type(Player_obj->instance, si_index);
2525
2526         Player->last_ship_flown_si_index = si_index;
2527 }
2528
2529 // ----------------------------------------------------------------------------
2530 // create a default player ship
2531 //
2532 //      parameters:             use_last_flown  => select ship that was last flown on a mission
2533 //                                              (this is a default parameter which is set to 1)
2534 //
2535 // returns:                     0 => success
2536 //               !0 => failure
2537 //
2538 int create_default_player_ship(int use_last_flown)
2539 {
2540         int     player_ship_class=-1, i;
2541
2542         // find the ship that matches the string stored in default_player_ship
2543
2544         if ( use_last_flown ) {
2545                 player_ship_class = Players[Player_num].last_ship_flown_si_index;
2546         }
2547         else {
2548                 for (i = 0; i < Num_ship_types; i++) {
2549                         if ( !stricmp(Ship_info[i].name, default_player_ship) ) {
2550                                 player_ship_class = i;
2551                                 Players[Player_num].last_ship_flown_si_index = player_ship_class;
2552                                 break;
2553                         }
2554                 }
2555
2556                 if (i == Num_ship_types)
2557                         return 1;
2558         }
2559
2560         update_player_ship(player_ship_class);
2561
2562         // debug code to keep using descent style physics if the player starts a new game
2563 #ifndef NDEBUG
2564         if ( use_descent ) {
2565                 use_descent = 0;
2566                 toggle_player_object();
2567         }
2568 #endif
2569
2570         return 0;
2571 }
2572
2573 // return the original ship class for the specified slot
2574 int ss_return_original_ship_class(int slot_num)
2575 {
2576         int wnum, snum;
2577
2578         wnum = slot_num/4;
2579         snum = slot_num%4;
2580
2581         return Ss_wings[wnum].ss_slots[snum].original_ship_class;
2582 }
2583
2584 // return the ship arrival index for the slot (-1 means no ship arrival index)
2585 int ss_return_saindex(int slot_num)
2586 {
2587         int wnum, snum;
2588
2589         wnum = slot_num/4;
2590         snum = slot_num%4;
2591
2592         return Ss_wings[wnum].ss_slots[snum].sa_index;
2593 }
2594
2595 // ----------------------------------------------------------------------------
2596 // ss_return_ship()
2597 //
2598 // For a given wing slot, return the ship index if the ship has been created.  
2599 // Otherwise, find the index into ship_arrivals[] for the ship
2600 //
2601 //      input:  wing_block      =>              wing block of ship to find
2602 //                              wing_slot       =>              wing slot of ship to find
2603 //                              ship_index      =>              OUTPUT parameter: the Ships[] index of the ship in the wing slot
2604 //                                                                              This value will be -1 if there is no ship created yet
2605 //                              ppobjp          =>              OUTPUT parameter: returns a pointer to a parse object for
2606 //                                                                              the ship that hasn't been created yet.  Set to NULL if the
2607 //                                                                              ship has already been created
2608 //
2609 // returns:     the original ship class of the ship, or -1 if the ship doesn't exist
2610 //
2611 // NOTE: For the player wing, the player is not yet in the wp->ship_index[].. so
2612 // that is why there is an offset of 1 when getting ship indicies from the player
2613 // wing.  The player is special cased by looking at the status of the wing slot
2614 //
2615 int ss_return_ship(int wing_block, int wing_slot, int *ship_index, p_object **ppobjp)
2616 {
2617         *ship_index = -1;
2618         *ppobjp = NULL;
2619
2620         ss_slot_info    *ws;
2621
2622         if (!Wss_num_wings) {
2623                 *ppobjp = NULL;
2624                 *ship_index = Player_obj->instance;
2625                 return Player_ship->ship_info_index;
2626         }
2627
2628         if ( Ss_wings[wing_block].wingnum < 0 ) {
2629                 return -1;
2630         }
2631
2632         ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2633
2634         // Check to see if ship is on the ship_arrivals[] list
2635         if ( ws->sa_index != -1 ) {
2636                 *ship_index = -1;
2637                 *ppobjp = &ship_arrivals[ws->sa_index];
2638         } else {
2639                 *ship_index = Wings[Ss_wings[wing_block].wingnum].ship_index[wing_slot];
2640                 Assert(*ship_index != -1);              
2641         }
2642
2643         return ws->original_ship_class;
2644 }
2645
2646 // return the name of the ship in the specified wing position... if the ship is the
2647 // player ship, return the player callsign
2648 //
2649 // input: ensure at least NAME_LENGTH bytes allocated for name buffer
2650 void ss_return_name(int wing_block, int wing_slot, char *name)
2651 {
2652         ss_slot_info    *ws;
2653         wing                            *wp;
2654
2655         ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2656         wp = &Wings[Ss_wings[wing_block].wingnum];              
2657
2658         if (!Wss_num_wings) {
2659                 strcpy(name, Player->callsign);
2660                 return;
2661         }
2662
2663         // Check to see if ship is on the ship_arrivals[] list
2664         if ( ws->sa_index != -1 ) {
2665                 strcpy(name, ship_arrivals[ws->sa_index].name);
2666         } else {
2667                 ship *sp;
2668                 sp = &Ships[wp->ship_index[wing_slot]];
2669
2670                 // in multiplayer, return the callsigns of the players who are in the ships
2671                 if(Game_mode & GM_MULTIPLAYER){
2672                         int player_index = multi_find_player_by_object(&Objects[sp->objnum]);
2673                         if(player_index != -1){
2674                                 strcpy(name,Net_players[player_index].player->callsign);
2675                         } else {
2676                                 strcpy(name,sp->ship_name);
2677                         }
2678                 } else {                
2679                         strcpy(name, sp->ship_name);
2680                 }
2681         }
2682 }
2683
2684 int ss_get_selected_ship()
2685 {
2686         return Selected_ss_class;
2687 }
2688
2689 // Set selected ship to the first occupied wing slot, or first ship in pool if no slots are occupied
2690 void ss_reset_selected_ship()
2691 {
2692         int i;
2693
2694         Selected_ss_class = -1;
2695
2696         if ( Wss_num_wings <= 0 ) {
2697                 Selected_ss_class = Team_data[Common_team].default_ship;
2698                 return;
2699         }
2700
2701         // get first ship class found on slots
2702         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2703                 if ( Wss_slots[i].ship_class >= 0 ) {
2704                         Selected_ss_class = Wss_slots[i].ship_class;
2705                         break;
2706                 }
2707         }
2708
2709         if ( Selected_ss_class == -1 ) {
2710                 Int3();
2711                 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2712                         if ( Ss_pool[i] > 0 ) {
2713                                 Selected_ss_class = i;
2714                         }
2715                 }
2716         }
2717
2718         if ( Selected_ss_class == -1 ) {
2719                 Int3();
2720                 return;
2721         }
2722 }
2723
2724 // There may be ships that are in wings but not in Team_data[0].  Since we still want to show those
2725 // icons in the ship selection list, the code below checks for these cases.  If a ship is found in
2726 // a wing, and is not in Team_data[0], it is appended to the end of the ship_count[] and ship_list[] arrays
2727 // that are in Team_data[0]
2728 //
2729 // exit: number of distinct ship classes available to choose from
2730 int ss_fixup_team_data(team_data *tdata)
2731 {
2732         int i, j, k, ship_in_parse_player, list_size;
2733         p_object                *p_objp;
2734         team_data       *p_team_data;
2735
2736         p_team_data = tdata;
2737         ship_in_parse_player = 0;
2738         list_size = p_team_data->number_choices;
2739
2740         for ( i = 0; i < MAX_PLAYER_WINGS; i++ ) {
2741                 wing *wp;
2742                 if ( Starting_wings[i] == -1 )
2743                         continue;
2744                 wp = &Wings[Starting_wings[i]];
2745                 for ( j = 0; j < wp->current_count; j++ ) {
2746                         ship_in_parse_player = 0;
2747                         
2748                         for ( k = 0; k < p_team_data->number_choices; k++ ) {
2749                                 Assert( p_team_data->ship_count[k] >= 0 );
2750                                 if ( p_team_data->ship_list[k] == Ships[wp->ship_index[j]].ship_info_index ) {
2751                                         ship_in_parse_player = 1;
2752                                         break;
2753                                 }
2754                         }       // end for, go to next item in parse player
2755
2756                         if ( !ship_in_parse_player ) {
2757                                 p_team_data->ship_count[list_size] = 0;
2758                                 p_team_data->ship_list[list_size] = Ships[wp->ship_index[j]].ship_info_index;
2759                                 p_team_data->number_choices++;
2760                                 list_size++;
2761                         }
2762                 }       // end for, go get next ship in wing
2763
2764                 if ( wp->current_count == 0 ) {
2765
2766                         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2767                                 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2768                                         ship_in_parse_player = 0;
2769                         
2770                                         for ( k = 0; k < p_team_data->number_choices; k++ ) {
2771                                                 Assert( p_team_data->ship_count[k] >= 0 );
2772                                                 if ( p_team_data->ship_list[k] == p_objp->ship_class ) {
2773                                                         ship_in_parse_player = 1;
2774                                                         break;
2775                                                 }
2776                                         }       // end for, go to next item in parse player
2777
2778                                         if ( !ship_in_parse_player ) {
2779                                                 p_team_data->ship_count[list_size] = 0;
2780                                                 p_team_data->ship_list[list_size] = p_objp->ship_class;
2781                                                 p_team_data->number_choices++;
2782                                                 list_size++;
2783                                         }
2784                                 }
2785                         }
2786                 }
2787         }       // end for, go to next wing
2788
2789         if ( list_size == 0 ) {
2790                 // ensure that the default player ship is in the ship_list too
2791                 ship_in_parse_player = 0;
2792                 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2793                         Assert( p_team_data->ship_count[k] >= 0 );
2794                         if ( p_team_data->ship_list[k] == p_team_data->default_ship ) {
2795                                 ship_in_parse_player = 1;
2796                                 break;
2797                         }
2798                 }
2799                 if ( !ship_in_parse_player ) {
2800                         p_team_data->ship_count[list_size] = 0;
2801                         p_team_data->ship_list[list_size] = p_team_data->default_ship;
2802                         p_team_data->number_choices++;
2803                         list_size++;
2804                 }
2805         }
2806
2807         return list_size;
2808 }
2809
2810 // set numbers of ships in pool to default values
2811 void ss_init_pool(team_data *pteam)
2812 {
2813         int i;
2814
2815         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2816                 Ss_pool[i] = -1;
2817         }
2818
2819         // set number of available ships based on counts in team_data
2820         for ( i = 0; i < pteam->number_choices; i++ ) {
2821                 Ss_pool[pteam->ship_list[i]] = pteam->ship_count[i];
2822         }
2823 }
2824
2825 // load the icons for a specific ship class
2826 void ss_load_icons(int ship_class)
2827 {
2828         ss_icon_info    *icon;
2829         int                             first_frame, num_frames, i;
2830
2831         icon = &Ss_icons[ship_class];
2832
2833         first_frame = bm_load_animation(Ship_info[ship_class].icon_filename, &num_frames);
2834         if ( first_frame == -1 ) {
2835                 Int3(); // Could not load in icon frames.. get Alan
2836                 return;
2837         }
2838
2839         for ( i = 0; i < num_frames; i++ ) {
2840                 icon->icon_bmaps[i] = first_frame+i;
2841         }
2842
2843         // set the current bitmap for the ship icon
2844         icon->current_icon_bitmap = icon->icon_bmaps[ICON_FRAME_NORMAL];
2845 }
2846
2847 // load all the icons for ships in the pool
2848 void ss_load_all_icons()
2849 {
2850         #ifndef DEMO // not for FS2_DEMO
2851
2852         int i, j;
2853
2854         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2855                 // clear out data
2856                 Ss_icons[i].current_icon_bitmap = -1;
2857                 Ss_icons[i].anim = NULL;
2858                 Ss_icons[i].anim_instance = NULL;
2859                 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
2860                         Ss_icons[i].icon_bmaps[j] = -1;
2861                 }
2862
2863                 if ( Ss_pool[i] >= 0 ) {
2864                         ss_load_icons(i);
2865                 }
2866         }
2867
2868         #endif
2869 }
2870
2871 // Load in a specific ship animation.  The data is loaded as a memory-mapped file since these animations
2872 // are awfully big.
2873 void ss_load_anim(int ship_class)
2874 {
2875         ss_icon_info    *icon;
2876
2877         icon = &Ss_icons[ship_class];
2878
2879         // load the compressed ship animation into memory 
2880         // NOTE: if last parm of load_anim is 1, the anim file is mapped to memory 
2881         Assert( icon->anim == NULL );
2882         icon->anim = ss_load_individual_animation(ship_class);
2883         if ( icon->anim == NULL ) {
2884                 Int3();         // couldn't load anim filename.. get Alan
2885         }
2886 }
2887
2888 // Load in any ship animations.  This function assumes that Ss_pool has been inited.
2889 void ss_load_all_anims()
2890 {
2891         #ifndef DEMO // not for FS2_DEMO
2892
2893         int i;
2894
2895         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2896                 if ( Ss_pool[i] > 0 ) {
2897                         ss_load_anim(i);
2898                 }
2899         }
2900
2901         #endif
2902 }
2903
2904 // determine if the slot is disabled
2905 int ss_disabled_slot(int slot_num)
2906 {
2907         if ( Wss_num_wings <= 0 ){
2908                 return 0;
2909         }
2910
2911         // HACK HACK HACK - call the team select function in multiplayer
2912         if(Game_mode & GM_MULTIPLAYER) {
2913                 return multi_ts_disabled_slot(slot_num);
2914         } 
2915         return ( Ss_wings[slot_num/4].ss_slots[slot_num%4].status & WING_SLOT_IGNORE );
2916 }
2917
2918 // reset the slot data
2919 void ss_clear_slots()
2920 {
2921         int                             i,j;
2922         ss_slot_info    *slot;
2923
2924         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2925                 Wss_slots[i].ship_class = -1;
2926         }
2927
2928         for ( i = 0; i < 3; i++ ) {
2929                 for ( j = 0; j < 4; j++ ) {
2930                         slot = &Ss_wings[i].ss_slots[j];
2931                         slot->status = WING_SLOT_DISABLED;
2932                         slot->sa_index = -1;
2933                         slot->original_ship_class = -1;
2934                 }
2935         }
2936 }
2937
2938 // initialize all wing struct stuff
2939 void ss_clear_wings()
2940 {
2941         int idx;
2942
2943         for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
2944                 Ss_wings[idx].wingnum = -1;
2945                 Ss_wings[idx].num_slots = 0;
2946                 Ss_wings[idx].is_late = 0;
2947         }
2948 }
2949
2950 // set up Wss_num_wings and Wss_wings[] based on Starting_wings[] info
2951 void ss_init_wing_info(int wing_num,int starting_wing_num)
2952 {
2953         wing                            *wp;
2954         ss_wing_info    *ss_wing;
2955         ss_slot_info    *slot;
2956                 
2957         ss_wing = &Ss_wings[wing_num];  
2958
2959         if ( Starting_wings[starting_wing_num] < 0 ) {
2960                 return;
2961         }
2962
2963         ss_wing->wingnum = Starting_wings[starting_wing_num];
2964         Wss_num_wings++;
2965
2966         wp = &Wings[Ss_wings[wing_num].wingnum];
2967         ss_wing->num_slots = wp->current_count;
2968
2969         if ( wp->current_count == 0 || wp->ship_index[0] == -1 ) {
2970                 p_object *p_objp;
2971                 // Temporarily fill in the current count and initialize the ship list in the wing
2972                 // This gets cleaned up before the mission is started
2973                 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2974                         if ( p_objp->wingnum == WING_INDEX(wp) ) {
2975                                 slot = &ss_wing->ss_slots[ss_wing->num_slots++];
2976                                 slot->sa_index = p_objp-ship_arrivals;
2977                                 slot->original_ship_class = p_objp->ship_class;
2978                         }
2979                         ss_wing->is_late = 1;
2980                 }
2981         }       
2982 }
2983
2984 // Determine if a ship is actually a console player ship
2985 int ss_wing_slot_is_console_player(int index)
2986 {
2987         int wingnum, slotnum;
2988         
2989         wingnum=index/4;
2990         slotnum=index%4;
2991
2992         if ( wingnum >= Wss_num_wings ) {
2993                 return 0;
2994         }
2995
2996         if ( Ss_wings[wingnum].ss_slots[slotnum].status & WING_SLOT_IS_PLAYER ) {
2997                 return 1;
2998         }
2999
3000         return 0;
3001 }
3002
3003 // init the ship selection portion of the units, and set up the ui data
3004 void ss_init_units()
3005 {
3006         int                             i,j;
3007         wing                            *wp;
3008         ss_slot_info    *ss_slot;
3009         ss_wing_info    *ss_wing;       
3010
3011         for ( i = 0; i < Wss_num_wings; i++ ) {
3012
3013                 ss_wing = &Ss_wings[i];
3014
3015                 if ( ss_wing->wingnum < 0 ) {
3016                         Int3();
3017                         continue;
3018                 }
3019
3020                 wp = &Wings[ss_wing->wingnum];
3021
3022                 for ( j = 0; j < ss_wing->num_slots; j++ ) {
3023                                 
3024                         ss_slot = &ss_wing->ss_slots[j];
3025
3026                         if ( ss_slot->sa_index == -1 ) {
3027                                 ss_slot->original_ship_class = Ships[wp->ship_index[j]].ship_info_index;
3028                         }
3029         
3030                         // Set the type of slot.  Check if the slot is marked as locked, if so then the player is not
3031                         // going to be able to modify that ship.
3032                         if ( ss_slot->sa_index == -1 ) {
3033                                 int objnum;
3034                                 if ( Ships[wp->ship_index[j]].flags & SF_LOCKED ) {
3035                                         ss_slot->status = WING_SLOT_DISABLED;
3036                                         ss_slot->status |= WING_SLOT_LOCKED;
3037                                 } else {
3038                                         ss_slot->status = WING_SLOT_FILLED;
3039                                 }
3040
3041                                 objnum = Ships[wp->ship_index[j]].objnum;
3042                                 if ( Objects[objnum].flags & OF_PLAYER_SHIP ) {
3043                                         if ( ss_slot->status & WING_SLOT_LOCKED ) {
3044                                                 // Int3();      // Get Alan
3045                                                 
3046                                                 // just unflag it
3047                                                 ss_slot->status &= ~(WING_SLOT_LOCKED);
3048                                         }
3049                                         ss_slot->status = WING_SLOT_FILLED;
3050                                         if ( objnum == OBJ_INDEX(Player_obj) ) {
3051                                                 ss_slot->status |= WING_SLOT_IS_PLAYER;
3052                                         }
3053                                 }
3054                         } else {
3055                                 if ( ship_arrivals[ss_slot->sa_index].flags & P_SF_LOCKED ) {
3056                                         ss_slot->status = WING_SLOT_DISABLED;
3057                                         ss_slot->status |= WING_SLOT_LOCKED;
3058                                 } else {
3059                                         ss_slot->status = WING_SLOT_FILLED;
3060                                 }
3061                                 if ( ship_arrivals[ss_slot->sa_index].flags & P_OF_PLAYER_START ) {
3062                                         if ( ss_slot->status & WING_SLOT_LOCKED ) {
3063                                                 // Int3();      // Get Alan
3064
3065                                                 // just unflag it
3066                                                 ss_slot->status &= ~(WING_SLOT_LOCKED);
3067                                         }
3068                                         ss_slot->status = WING_SLOT_FILLED;
3069                                         ss_slot->status |= WING_SLOT_IS_PLAYER;
3070                                 }
3071                         }
3072
3073                         // Assign the ship class to the unit
3074                         Wss_slots[i*4+j].ship_class = ss_slot->original_ship_class;
3075
3076                 }       // end for
3077         }       // end for
3078
3079         // lock/unlock any necessary slots for multiplayer
3080         if(Game_mode & GM_MULTIPLAYER){
3081                 ss_recalc_multiplayer_slots();
3082         }
3083 }
3084
3085 // set the necessary pointers
3086 void ss_set_team_pointers(int team)
3087 {
3088         Ss_wings = Ss_wings_teams[team];
3089         Ss_icons = Ss_icons_teams[team];
3090         Ss_pool = Ss_pool_teams[team];
3091         Wl_pool = Wl_pool_teams[team];
3092         Wss_slots = Wss_slots_teams[team];
3093 }
3094
3095 // initialize team specific stuff
3096 void ship_select_init_team_data(int team_num)
3097 {                       
3098         int idx;
3099
3100         // set up the pointers to initialize the data structures.
3101         Ss_wings = Ss_wings_teams[team_num];
3102         Ss_icons = Ss_icons_teams[team_num];
3103         Ss_pool = Ss_pool_teams[team_num];
3104         Wl_pool = Wl_pool_teams[team_num];
3105         Wss_slots = Wss_slots_teams[team_num];
3106         
3107         ss_fixup_team_data(&Team_data[team_num]);
3108         ss_init_pool(&Team_data[team_num]);
3109         
3110         ss_clear_slots();               // reset data for slots 
3111         ss_clear_wings();
3112
3113         // determine how many wings we should be checking for
3114         Wss_num_wings = 0;
3115         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3116                 // now setup wings for easy reference           
3117                 ss_init_wing_info(0,team_num);                  
3118         } else {                        
3119                 // now setup wings for easy reference
3120                 for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
3121                         ss_init_wing_info(idx,idx);     
3122                 }
3123         }
3124         
3125
3126         // if there are no wings, don't call the init_units() function
3127         if ( Wss_num_wings <= 0 ) {
3128                 Wss_slots[0].ship_class = Team_data[team_num].default_ship;
3129                 return;
3130         }
3131
3132         ss_init_units();        
3133 }
3134
3135 // called when the briefing is entered
3136 void ship_select_common_init()
3137 {               
3138         int idx;
3139
3140         // initialize team critical data for all teams
3141         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){                
3142                 // initialize for all teams in the game
3143                 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){        
3144                         ship_select_init_team_data(idx);
3145                 }               
3146
3147                 // finally, intialize team data for myself
3148                 ship_select_init_team_data(Common_team);
3149         } else {                        
3150                 ship_select_init_team_data(Common_team);
3151         }
3152         
3153         init_active_list();
3154
3155         // load the necessary icons/animations
3156         ss_load_all_icons();
3157         ss_load_all_anims();
3158
3159         ss_reset_selected_ship();
3160         ss_reset_carried_icon();
3161 }
3162
3163 // change any interface data based on updated Wss_slots[] and Ss_pool[]
3164 void ss_synch_interface()
3165 {
3166         int                             i;
3167         ss_slot_info    *slot;
3168
3169         int old_list_start = SS_active_list_start;
3170
3171         init_active_list();     // build the list of pool ships
3172
3173         if ( old_list_start < SS_active_list_size ) {
3174                 SS_active_list_start = old_list_start;
3175         }
3176
3177         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
3178                 slot = &Ss_wings[i/4].ss_slots[i%4];
3179
3180                 if ( Wss_slots[i].ship_class == -1 ) {
3181                         if ( slot->status & WING_SLOT_FILLED ) {
3182                                 slot->status &= ~WING_SLOT_FILLED;
3183                                 slot->status |= WING_SLOT_EMPTY;
3184                         }
3185                 } else {
3186                         if ( slot->status & WING_SLOT_EMPTY ) {
3187                                 slot->status &= ~WING_SLOT_EMPTY;
3188                                 slot->status |= WING_SLOT_FILLED;
3189                         }
3190                 }
3191         }
3192 }
3193
3194 // exit: data changed flag
3195 int ss_swap_slot_slot(int from_slot, int to_slot, int *sound)
3196 {
3197         int i, tmp, fwnum, fsnum, twnum, tsnum;
3198
3199         if ( from_slot == to_slot ) {
3200                 *sound=SND_ICON_DROP_ON_WING;
3201                 return 0;
3202         }
3203
3204         // ensure from_slot has a ship to pick up
3205         if ( Wss_slots[from_slot].ship_class < 0 ) {
3206                 *sound=SND_ICON_DROP;
3207                 return 0;
3208         }
3209
3210         fwnum = from_slot/4;
3211         fsnum = from_slot%4;
3212
3213         twnum = to_slot/4;
3214         tsnum = to_slot%4;
3215
3216         // swap ship class
3217         tmp = Wss_slots[from_slot].ship_class;
3218         Wss_slots[from_slot].ship_class = Wss_slots[to_slot].ship_class;
3219         Wss_slots[to_slot].ship_class = tmp;
3220
3221         // swap weapons
3222         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3223                 tmp = Wss_slots[from_slot].wep[i];
3224                 Wss_slots[from_slot].wep[i] = Wss_slots[to_slot].wep[i];
3225                 Wss_slots[to_slot].wep[i] = tmp;
3226
3227                 tmp = Wss_slots[from_slot].wep_count[i];
3228                 Wss_slots[from_slot].wep_count[i] = Wss_slots[to_slot].wep_count[i];
3229                 Wss_slots[to_slot].wep_count[i] = tmp;
3230         }
3231
3232         *sound=SND_ICON_DROP_ON_WING;
3233         return 1;
3234 }
3235
3236 // exit: data changed flag
3237 int ss_dump_to_list(int from_slot, int to_list, int *sound)
3238 {
3239         int i, fwnum, fsnum;
3240         wss_unit        *slot;
3241
3242         slot = &Wss_slots[from_slot];
3243
3244         // ensure from_slot has a ship to pick up
3245         if ( slot->ship_class < 0 ) {
3246                 *sound=SND_ICON_DROP;
3247                 return 0;
3248         }
3249
3250         fwnum = from_slot/4;
3251         fsnum = from_slot%4;
3252
3253         // put ship back in list
3254         Ss_pool[to_list]++;             // return to list
3255         slot->ship_class = -1;  // remove from slot
3256
3257         // put weapons back in list
3258         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3259                 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3260                         Wl_pool[slot->wep[i]] += slot->wep_count[i];
3261                         slot->wep[i] = -1;
3262                         slot->wep_count[i] = 0;
3263                 }
3264         }
3265
3266         *sound=SND_ICON_DROP;
3267         return 1;
3268 }
3269
3270 // exit: data changed flag
3271 int ss_grab_from_list(int from_list, int to_slot, int *sound)
3272 {
3273         wss_unit        *slot;
3274         int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3275
3276         slot = &Wss_slots[to_slot];
3277
3278         // ensure that pool has ship
3279         if ( Ss_pool[from_list] <= 0 ) {
3280                 *sound=SND_ICON_DROP;
3281                 return 0;
3282         }
3283
3284         Assert(slot->ship_class < 0 );  // slot should be empty
3285
3286         // take ship from list->slot
3287         Ss_pool[from_list]--;
3288         slot->ship_class = from_list;
3289
3290         // take weapons from list->slot
3291         wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3292         wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3293         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3294                 slot->wep[i] = wep[i];
3295                 slot->wep_count[i] = wep_count[i];
3296         }
3297
3298         *sound=SND_ICON_DROP_ON_WING;
3299         return 1;
3300 }
3301
3302 // exit: data changed flag
3303 int ss_swap_list_slot(int from_list, int to_slot, int *sound)
3304 {
3305         int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3306         wss_unit        *slot;
3307
3308         // ensure that pool has ship
3309         if ( Ss_pool[from_list] <= 0 ) {
3310                 *sound=SND_ICON_DROP;
3311                 return 0;
3312         }
3313
3314         slot = &Wss_slots[to_slot];
3315         Assert(slot->ship_class >= 0 ); // slot should be filled
3316
3317         // put ship from slot->list
3318         Ss_pool[Wss_slots[to_slot].ship_class]++;
3319
3320         // put weapons from slot->list
3321         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3322                 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3323                         Wl_pool[slot->wep[i]] += slot->wep_count[i];
3324                         slot->wep[i] = -1;
3325                         slot->wep_count[i] = 0;
3326                 }
3327         }
3328
3329         // take ship from list->slot
3330         Ss_pool[from_list]--;
3331         slot->ship_class = from_list;
3332
3333         // take weapons from list->slot
3334         wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3335         wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3336         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3337                 slot->wep[i] = wep[i];
3338                 slot->wep_count[i] = wep_count[i];
3339         }
3340
3341         *sound=SND_ICON_DROP_ON_WING;
3342         return 1;
3343 }
3344
3345 void ss_apply(int mode, int from_slot, int from_list, int to_slot, int to_list,int player_index)
3346 {
3347         int update=0;
3348         int sound=-1;
3349
3350         switch(mode){
3351         case WSS_SWAP_SLOT_SLOT:
3352                 update = ss_swap_slot_slot(from_slot, to_slot, &sound);
3353                 break;
3354         case WSS_DUMP_TO_LIST:
3355                 update = ss_dump_to_list(from_slot, to_list, &sound);
3356                 break;
3357         case WSS_GRAB_FROM_LIST:
3358                 update = ss_grab_from_list(from_list, to_slot, &sound);
3359                 break;
3360         case WSS_SWAP_LIST_SLOT:
3361                 update = ss_swap_list_slot(from_list, to_slot, &sound);
3362                 break;
3363         }
3364
3365         // only play this sound if the move was done locally (by the host in other words)
3366         if ( (sound >= 0) && (player_index == -1) ) {
3367                 gamesnd_play_iface(sound);              
3368         }
3369
3370         if ( update ) {
3371                 // NO LONGER USED - THERE IS A MULTIPLAYER VERSION OF THIS SCREEN NOW
3372                 /*
3373                 if ( MULTIPLAYER_HOST ) {
3374                         int size;
3375                         ubyte wss_data[MAX_PACKET_SIZE-20];
3376                         size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound);
3377                         send_wss_update_packet(wss_data, size, player_index);
3378                 }
3379                 */
3380
3381                 ss_synch_interface();
3382         }
3383 }
3384
3385 void ss_drop(int from_slot,int from_list,int to_slot,int to_list,int player_index)
3386 {
3387         int mode;
3388         common_flash_button_init();
3389         
3390         mode = wss_get_mode(from_slot, from_list, to_slot, to_list, -1);
3391         if ( mode >= 0 ) {
3392                 ss_apply(mode, from_slot, from_list, to_slot, to_list,player_index);
3393         }       
3394 }
3395
3396 // lock/unlock any necessary slots for multiplayer
3397 void ss_recalc_multiplayer_slots()
3398 {
3399         int                             i,j,objnum;
3400         wing                            *wp;
3401         ss_slot_info    *ss_slot;
3402         ss_wing_info    *ss_wing;
3403         
3404         // no wings
3405         if ( Wss_num_wings <= 0 ) {
3406                 Wss_slots[0].ship_class = Team_data[Common_team].default_ship;;
3407                 return;
3408         }
3409
3410         for ( i = 0; i < Wss_num_wings; i++ ) {
3411                 ss_wing = &Ss_wings[i];
3412                 if ( ss_wing->wingnum < 0 ) {
3413                         Int3();
3414                         continue;
3415                 }
3416
3417                 // NOTE : the method below will eventually have to change to account for all possible netgame options
3418                 
3419                 // get the wing pointer
3420                 wp = &Wings[ss_wing->wingnum];          
3421                 for ( j = 0; j < ss_wing->num_slots; j++ ) {                            
3422                         // get the objnum of the ship in this slot
3423                         objnum = Ships[wp->ship_index[j]].objnum;
3424
3425                         // get the slot pointer
3426                         ss_slot = &ss_wing->ss_slots[j];                        
3427                         
3428                         if (ss_slot->sa_index == -1) {                                  
3429                                 // lock all slots by default
3430                                 ss_slot->status |= WING_SLOT_LOCKED;
3431                                 
3432                                 // if this is my slot, then unlock it
3433                                 if(!multi_ts_disabled_slot((i*4)+j)){                           
3434                                         ss_slot->status &= ~WING_SLOT_LOCKED;
3435                                 }
3436                         }
3437                 }
3438         }
3439
3440