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