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