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