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