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