]> icculus.org git repositories - taylor/freespace2.git/blob - src/missionui/missionscreencommon.cpp
Initial revision
[taylor/freespace2.git] / src / missionui / missionscreencommon.cpp
1 /*
2  * $Logfile: /Freespace2/code/MissionUI/MissionScreenCommon.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.1  2002/05/03 03:28:10  root
9  * Initial revision
10  *
11  * 
12  * 13    10/14/99 2:51p Jefff
13  * localiztion fixes
14  * 
15  * 12    8/05/99 3:40p Jefff
16  * hi-res text adjustments
17  * 
18  * 11    7/15/99 9:20a Andsager
19  * FS2_DEMO initial checkin
20  * 
21  * 10    2/01/99 5:55p Dave
22  * Removed the idea of explicit bitmaps for buttons. Fixed text
23  * highlighting for disabled gadgets.
24  * 
25  * 9     1/30/99 7:33p Neilk
26  * Fixed coords problems for mission briefing screens
27  * 
28  * 8     1/30/99 5:08p Dave
29  * More new hi-res stuff.Support for nice D3D textures.
30  * 
31  * 7     1/29/99 4:17p Dave
32  * New interface screens.
33  * 
34  * 6     1/24/99 11:37p Dave
35  * First full rev of beam weapons. Very customizable. Removed some bogus
36  * Int3()'s in low level net code.
37  * 
38  * 5     11/30/98 1:07p Dave
39  * 16 bit conversion, first run.
40  * 
41  * 4     11/17/98 11:12a Dave
42  * Removed player identification by address. Now assign explicit id #'s.
43  * 
44  * 3     10/16/98 9:40a Andsager
45  * Remove ".h" files from model.h
46  * 
47  * 2     10/07/98 10:53a Dave
48  * Initial checkin.
49  * 
50  * 1     10/07/98 10:50a Dave
51  * 
52  * 85    6/09/98 10:31a Hoffoss
53  * Created index numbers for all xstr() references.  Any new xstr() stuff
54  * added from here on out should be added to the end if the list.  The
55  * current list count can be found in FreeSpace.cpp (search for
56  * XSTR_SIZE).
57  * 
58  * 84    5/08/98 7:52p Lawrance
59  * fix bug where wing slot icons were not getting loaded
60  * 
61  * 83    5/08/98 10:17a Lawrance
62  * don't play briefing slide-in animation if detail level is below high
63  * 
64  * 82    5/06/98 11:50p Lawrance
65  * Clean up help overlay code for loadout screens
66  * 
67  * 81    5/03/98 1:55a Lawrance
68  * Fix some sound problems with loadout screens
69  * 
70  * 80    4/30/98 6:03p Lawrance
71  * Make drag and drop work better.
72  * 
73  * 79    4/22/98 5:52p Dave
74  * Large reworking of endgame sequencing. Updated host options screen for
75  * new artwork. Put in checks to end game if host leaves or if team
76  * captains leave mid-game. 
77  * 
78  * 78    4/07/98 7:51p Hoffoss
79  * Implemented changed to options screen due to artwork changes.
80  * 
81  * 77    4/07/98 5:42p Dave
82  * Put in support for ui display of voice system status (recording,
83  * playing back, etc). Make sure main hall music is stopped before
84  * entering a multiplayer game via ingame join.
85  * 
86  * 76    4/02/98 11:40a Lawrance
87  * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
88  * 
89  * 75    4/01/98 11:19p Dave
90  * Put in auto-loading of xferred pilot pic files. Grey out background
91  * behind pinfo popup. Put a chatbox message in when players are kicked.
92  * Moved mission title down in briefing. Other ui fixes.
93  * 
94  * 74    4/01/98 9:21p John
95  * Made NDEBUG, optimized build with no warnings or errors.
96  * 
97  * 73    3/31/98 11:47p Lawrance
98  * Fix some bugs related to wingmen selection when doing a quick mission
99  * restart.
100  * 
101  * 72    3/31/98 5:31p Lawrance
102  * Fix sound bug that happenned when entering briefing
103  * 
104  * 71    3/30/98 5:16p Lawrance
105  * centralize a check for disabled loadout screens
106  * 
107  * 70    3/30/98 12:18a Lawrance
108  * change some DEMO_RELEASE code to not compile code rather than return
109  * early
110  * 
111  * 69    3/29/98 10:16p Allender
112  * scramble missions need to have ship/weapon selection disabled (this
113  * code was somehow lost)
114  * 
115  * 68    3/29/98 1:24p Dave
116  * Make chatbox not clear between multiplayer screens. Select player ship
117  * as default in mp team select and weapons select screens. Made create
118  * game mission list use 2 fixed size columns.
119  * 
120  * 67    3/29/98 12:55a Lawrance
121  * Get demo build working with limited set of data.
122  * 
123  * 66    3/25/98 8:43p Hoffoss
124  * Changed anim_play() to not be so damn complex when you try and call it.
125  * 
126  * 65    3/24/98 4:59p Dave
127  * Fixed several ui bugs. Put in pre and post voice stream playback sound
128  * fx. Put in error specific popups for clients getting dropped from games
129  * through actions other than their own.
130  * 
131  * 64    3/19/98 5:32p Lawrance
132  * Added music to the background of command brief screen.
133  * 
134  * 63    3/05/98 5:02p Dave
135  * More work on team vs. team support for multiplayer. Need to fix bugs in
136  * weapon select.
137  * 
138  * 62    3/03/98 8:55p Dave
139  * Finished pre-briefing team vs. team support.
140  * 
141  * 61    3/03/98 8:12p Lawrance
142  * Double timeout before flashing buttons
143  * 
144  * 60    3/02/98 3:27p Lawrance
145  * Don't call muti_ts_init() in single player
146  * 
147  * 59    3/01/98 3:26p Dave
148  * Fixed a few team select bugs. Put in multiplayer intertface sounds.
149  * Corrected how ships are disabled/enabled in team select/weapon select
150  * screens.
151  * 
152  * 58    2/27/98 4:55p Sandeep
153  * Fixed a signed/unsigned bug in the wss packet type
154  * 
155  * 57    2/26/98 4:59p Allender
156  * groundwork for team vs team briefings.  Moved weaponry pool into the
157  * Team_data structure.  Added team field into the p_info structure.
158  * Allow for mutliple structures in the briefing code.
159  * 
160  * 56    2/25/98 10:24a Lawrance
161  * Don't ask for confirmation when ESC is pressed.
162  * 
163  * 55    2/24/98 12:22a Lawrance
164  * New coords for revamped briefing graphics
165  * 
166  * 54    2/22/98 4:17p John
167  * More string externalization classification... 190 left to go!
168  * 
169  * 53    2/22/98 12:19p John
170  * Externalized some strings
171  * 
172  * 52    2/21/98 2:50p Lawrance
173  * Tell players that their campaign position will get saved if they return
174  * to main hall from loadout screens.
175  * 
176  * 51    2/19/98 6:26p Dave
177  * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
178  * initial support for player data uploading.
179  * 
180  * 50    2/18/98 3:56p Dave
181  * Several bugs fixed for mp team select screen. Put in standalone packet
182  * routing for team select.
183  * 
184  * 49    2/17/98 6:07p Dave
185  * Tore out old multiplayer team select screen, installed new one.
186  * 
187  * 48    2/13/98 3:46p Dave
188  * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
189  * functions.
190  * 
191  * 47    2/10/98 8:40p Dave
192  * Fixed some debriefing bugs.
193  * 
194  * 46    2/04/98 11:06p Lawrance
195  * Fix a couple of bugs with save/restore of player weapon loadout.
196  * 
197  * 45    2/04/98 4:32p Allender
198  * support for multiple briefings and debriefings.  Changes to mission
199  * type (now a bitfield).  Bitfield defs for multiplayer modes
200  * 
201  * 44    1/30/98 10:40a Lawrance
202  * remove any binding references to hotkey screen
203  * 
204  * 43    1/20/98 5:52p Lawrance
205  * prompt user before returning to main hall (in single player)
206  * 
207  * 42    1/17/98 5:51p Dave
208  * Bug fixes for bugs generated by multiplayer testing.
209  * 
210  * 41    1/14/98 11:39a Dave
211  * Polished up a bunch of popup support items.
212  * 
213  * 40    1/13/98 5:35p Lawrance
214  * Show popup when trying to go to weapons loadout without any ships
215  * selected.
216  * 
217  * 39    1/10/98 5:48p Lawrance
218  * Don't allow Tab to go to ship/weapon loadout screen in training, play
219  * negative feedback sounds if user tries to.
220  * 
221  * 38    1/10/98 12:45a Lawrance
222  * Don't restore loadout if mission was modified.
223  * 
224  * 37    1/09/98 6:06p Dave
225  * Put in network sound support for multiplayer ship/weapon select
226  * screens. Made clients exit game correctly through warp effect. Fixed
227  * main hall menu help overlay bug.
228  * 
229  * 36    1/09/98 11:04a Lawrance
230  * Fix bug that prevented buttons from flashing in the loadout screens.
231  * 
232  * 35    1/07/98 6:45p Lawrance
233  * Play first briefing music if none specified.
234  * 
235  * 34    1/05/98 4:57p Lawrance
236  * reset flash timers when a button is pressed or a key is pressed
237  * 
238  * 33    12/30/97 5:46p Lawrance
239  * Rename rnd() to rand_alt().
240  * 
241  * 32    12/30/97 4:27p Lawrance
242  * Add new rnd() function that doesn't affect rand() sequence.
243  * 
244  * 31    12/29/97 4:21p Lawrance
245  * Flash buttons on briefing/ship select/weapons loadout when enough time
246  * has elapsed without activity.
247  * 
248  * 30    12/28/97 5:52p Lawrance
249  * Add support for debriefing success/fail music.
250  * 
251  * 29    12/24/97 8:54p Lawrance
252  * Integrating new popup code
253  * 
254  * 28    12/24/97 1:19p Lawrance
255  * fix some bugs with the multiplayer ship/weapons loadout
256  * 
257  * 27    12/23/97 11:58a Allender
258  * changes to ship/wespon selection for multplayer.  added sounds to some
259  * interface screens.  Update and modiied end-of-briefing packets -- yet
260  * to be tested.
261  *
262  * $NoKeywords: $
263  *
264  */
265
266 #include <limits.h>
267 #include "freespace.h"
268 #include "eventmusic.h"
269 #include "key.h"
270 #include "missionscreencommon.h"
271 #include "missionshipchoice.h"
272 #include "missionweaponchoice.h"
273 #include "missionbrief.h"
274 #include "multi.h"
275 #include "multimsgs.h"
276 #include "timer.h"
277 #include "sound.h"
278 #include "gamesequence.h"
279 #include "bmpman.h"
280 // #include "movie.h"
281 #include "gamesnd.h"
282 #include "palman.h"
283 #include "mouse.h"
284 #include "contexthelp.h"
285 #include "chatbox.h"
286 #include "time.h"
287 #include "joy.h"
288 #include "cmdline.h"
289 #include "linklist.h"
290 #include "staticrand.h" // for rand_alt()
291 #include "popup.h"
292 #include "multiutil.h"
293 #include "multiteamselect.h"
294 #include "hudwingmanstatus.h"
295 #include "multi_endgame.h"
296 #include "uidefs.h"
297 #include "animplay.h"
298
299 //////////////////////////////////////////////////////////////////
300 // Game Globals
301 //////////////////////////////////////////////////////////////////
302
303 int Common_select_inited = 0;
304
305 // Dependent on when mouse button goes up
306 int Drop_icon_mflag, Drop_on_wing_mflag, Brief_mouse_up_flag;
307
308 int Mouse_down_last_frame = 0;
309
310 // Timers used to flash buttons after timeouts
311 #define MSC_FLASH_AFTER_TIME    60000           //      time before flashing a button
312 #define MSC_FLASH_INTERVAL              200             // time between flashes
313 int Flash_timer;                                                                //      timestamp used to start flashing
314 int Flash_toggle;                                                               // timestamp used to toggle flashing
315 int Flash_bright;                                                               // state of button to flash
316
317 //////////////////////////////////////////////////////////////////
318 // Global to modulde
319 //////////////////////////////////////////////////////////////////
320 int Current_screen;
321 int Next_screen;
322 static int InterfacePaletteBitmap = -1; // PCX file that holds the interface palette
323
324 //////////////////////////////////////////////////////////////////
325 // UI 
326 //////////////////////////////////////////////////////////////////
327 UI_WINDOW       *Active_ui_window;
328
329 brief_common_buttons Common_buttons[3][GR_NUM_RESOLUTIONS][NUM_COMMON_BUTTONS] = {      
330         {       // UGH
331                 { // GR_640
332                         brief_common_buttons("CB_00",                   7,              3,              37,     7,              0),
333                         brief_common_buttons("CB_01",                   7,              19,     37,     23,     1),
334                         brief_common_buttons("CB_02",                   7,              35,     37,     39,     2),
335                         brief_common_buttons("CB_05",                   571,    425,    572,    413,    5),
336                         brief_common_buttons("CB_06",                   533,    425,    500,    440,    6),
337                         brief_common_buttons("CB_07",                   533,    455,    479,    464,    7),                     
338                 }, 
339                 { // GR_1024                    
340                         brief_common_buttons("2_CB_00",         12,     5,              59,     12,     0),
341                         brief_common_buttons("2_CB_01",         12,     31,     59,     37,     1),
342                         brief_common_buttons("2_CB_02",         12,     56,     59,     62,     2),
343                         brief_common_buttons("2_CB_05",         914,    681,    937,    671,    5),
344                         brief_common_buttons("2_CB_06",         854,    681,    822,    704,    6),
345                         brief_common_buttons("2_CB_07",         854,    724,    800,    743,    7),                     
346                 }
347         },      
348         {       // UGH
349                 { // GR_640
350                         brief_common_buttons("CB_00",                   7,              3,              37,     7,              0),
351                         brief_common_buttons("CB_01",                   7,              19,     37,     23,     1),
352                         brief_common_buttons("CB_02",                   7,              35,     37,     39,     2),
353                         brief_common_buttons("CB_05",                   571,    425,    572,    413,    5),
354                         brief_common_buttons("CB_06",                   533,    425,    500,    440,    6),
355                         brief_common_buttons("CB_07",                   533,    455,    479,    464,    7),                     
356                 }, 
357                 { // GR_1024                    
358                         brief_common_buttons("2_CB_00",         12,     5,              59,     12,     0),
359                         brief_common_buttons("2_CB_01",         12,     31,     59,     37,     1),
360                         brief_common_buttons("2_CB_02",         12,     56,     59,     62,     2),
361                         brief_common_buttons("2_CB_05",         914,    681,    937,    671,    5),
362                         brief_common_buttons("2_CB_06",         854,    681,    822,    704,    6),
363                         brief_common_buttons("2_CB_07",         854,    724,    800,    743,    7),                     
364                 }
365         },      
366         {       // UGH
367                 { // GR_640
368                         brief_common_buttons("CB_00",                   7,              3,              37,     7,              0),
369                         brief_common_buttons("CB_01",                   7,              19,     37,     23,     1),
370                         brief_common_buttons("CB_02",                   7,              35,     37,     39,     2),
371                         brief_common_buttons("CB_05",                   571,    425,    572,    413,    5),
372                         brief_common_buttons("CB_06",                   533,    425,    500,    440,    6),
373                         brief_common_buttons("CB_07",                   533,    455,    479,    464,    7),                     
374                 }, 
375                 { // GR_1024                    
376                         brief_common_buttons("2_CB_00",         12,     5,              59,     12,     0),
377                         brief_common_buttons("2_CB_01",         12,     31,     59,     37,     1),
378                         brief_common_buttons("2_CB_02",         12,     56,     59,     62,     2),
379                         brief_common_buttons("2_CB_05",         914,    681,    937,    671,    5),
380                         brief_common_buttons("2_CB_06",         854,    681,    822,    704,    6),
381                         brief_common_buttons("2_CB_07",         854,    724,    800,    743,    7),                     
382                 }
383         }
384 };
385
386 #define COMMON_BRIEFING_BUTTON                                  0
387 #define COMMON_SS_BUTTON                                                        1
388 #define COMMON_WEAPON_BUTTON                                            2
389 #define COMMON_COMMIT_BUTTON                                            3
390 #define COMMON_HELP_BUTTON                                                      4
391 #define COMMON_OPTIONS_BUTTON                                           5
392
393 int Background_playing;                 // Flag to indicate background animation is playing
394 static anim *Background_anim;   // Ids for the anim data that is loaded
395
396 // value for which Team_data entry to use
397 int     Common_team;
398
399 // Ids for the instance of the anim that is playing
400 static anim_instance *Background_anim_instance;
401
402 int Wing_slot_empty_bitmap;
403 int Wing_slot_disabled_bitmap;
404
405 // prototypes
406 int wss_slots_all_empty();
407
408 // Display the no ships selected error
409 void common_show_no_ship_error()
410 {
411         popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "At least one ship must be selected before proceeding to weapons loadout", 460));
412 }
413
414 // Check the status of the buttons common to the loadout screens
415 void common_check_buttons()
416 {
417         int                     i;
418         UI_BUTTON       *b;
419
420         for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
421                 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
422                 if ( b->pressed() ) {
423                         
424                         common_button_do(i);
425                 }
426         }
427
428 /*
429         // AL 11-23-97: let a joystick button press commit
430         if ( joy_down_count(0) || joy_down_count(1) ) {
431                 Commit_pressed = 1;
432         }
433 */
434
435 }
436
437 // -------------------------------------------------------------------
438 // common_redraw_pressed_buttons()
439 //
440 // Redraw any common buttons that are pressed down.  This function is needed
441 // since we sometimes need to draw pressed buttons last to ensure the entire
442 // button gets drawn (and not overlapped by other buttons)
443 //
444 void common_redraw_pressed_buttons()
445 {
446         int                     i;
447         UI_BUTTON       *b;
448
449         for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
450                 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
451                 if ( b->button_down() ) {
452                         b->draw_forced(2);
453                 }
454         }
455 }
456
457 void common_buttons_maybe_reload(UI_WINDOW *ui_window)
458 {
459         UI_BUTTON       *b;
460         int                     i;
461
462         for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
463                 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
464                 b->set_bmaps(Common_buttons[Current_screen-1][gr_screen.res][i].filename);
465         }
466 }
467
468 void common_buttons_init(UI_WINDOW *ui_window)
469 {
470         UI_BUTTON       *b;
471         int                     i;
472
473         for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
474                 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
475                 b->create( ui_window, "", Common_buttons[Current_screen-1][gr_screen.res][i].x, Common_buttons[Current_screen-1][gr_screen.res][i].y,  60, 30, 0, 1);
476                 // set up callback for when a mouse first goes over a button
477                 b->set_highlight_action( common_play_highlight_sound );
478                 b->set_bmaps(Common_buttons[Current_screen-1][gr_screen.res][i].filename);
479                 b->link_hotspot(Common_buttons[Current_screen-1][gr_screen.res][i].hotspot);
480         }       
481
482         // add some text        
483         ui_window->add_XSTR("Briefing", 1504, Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].button, UI_XSTR_COLOR_GREEN);
484         ui_window->add_XSTR("Ship Selection", 1067, Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].button, UI_XSTR_COLOR_GREEN);
485         ui_window->add_XSTR("Weapon Loadout", 1068, Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].button, UI_XSTR_COLOR_GREEN);
486         ui_window->add_XSTR("Commit", 1062, Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].button, UI_XSTR_COLOR_PINK);
487         ui_window->add_XSTR("Help", 928, Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].button, UI_XSTR_COLOR_GREEN);
488         ui_window->add_XSTR("Options", 1036, Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].button, UI_XSTR_COLOR_GREEN);
489
490         common_reset_buttons();
491
492         Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
493         Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].button.set_hotkey(KEY_F1);
494         Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].button.set_hotkey(KEY_F2);
495
496         // for scramble or training missions, disable the ship/weapon selection regions
497         if ( brief_only_allow_briefing() ) {
498                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_REGION].button.disable();
499                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_REGION].button.disable();
500         }
501
502         #ifdef DEMO // allow for FS2_DEMO
503                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_REGION].button.disable();
504                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_REGION].button.disable();
505         #endif
506 }
507
508 void set_active_ui(UI_WINDOW *ui_window)
509 {
510         Active_ui_window = ui_window;
511 }
512
513 void common_music_init(int score_index)
514 {
515         if ( Cmdline_freespace_no_music ) {
516                 return;
517         }
518
519         if ( score_index >= NUM_SCORES ) {
520                 Int3();
521                 return;
522         }
523
524         if ( Mission_music[score_index] < 0 ) {
525                 if ( Num_music_files > 0 ) {
526                         Mission_music[score_index] = 0;
527                         nprintf(("Sound","No briefing music is selected, so play first briefing track: %s\n",Spooled_music[Mission_music[score_index]].name));
528                 } else {
529                         return;
530                 }
531         }
532
533         briefing_load_music( Spooled_music[Mission_music[score_index]].filename );
534         // Use this id to trigger the start of music playing on the briefing screen
535         Briefing_music_begin_timestamp = timestamp(BRIEFING_MUSIC_DELAY);
536 }
537
538 void common_music_do()
539 {
540         if ( Cmdline_freespace_no_music ) {
541                 return;
542         }
543
544         // Use this id to trigger the start of music playing on the briefing screen
545         if ( timestamp_elapsed( Briefing_music_begin_timestamp) ) {
546                 Briefing_music_begin_timestamp = 0;
547                 briefing_start_music();
548         }
549 }
550
551 void common_music_close()
552 {
553         if ( Cmdline_freespace_no_music ) {
554                 return;
555         }
556
557         if ( Num_music_files <= 0 )
558                 return;
559
560         briefing_stop_music();
561 }
562
563 // function that sets the current palette to the interface palette.  This function
564 // needs to be followed by common_free_interface_palette() to restore the game palette.
565 void common_set_interface_palette(char *filename)
566 {
567         static char buf[MAX_FILENAME_LEN + 1] = {0};
568
569         if (!filename)
570                 filename = NOX("palette01");
571
572         Assert(strlen(filename) <= MAX_FILENAME_LEN);
573         if ( (InterfacePaletteBitmap != -1) && !stricmp(filename, buf) )
574                 return;  // already set to this palette
575
576         strcpy(buf, filename);
577
578         // unload the interface bitmap from memory
579         if (InterfacePaletteBitmap != -1) {
580                 bm_unload(InterfacePaletteBitmap);
581                 InterfacePaletteBitmap = -1;
582         }
583
584         // ugh - we don't need this anymore
585         /*
586         InterfacePaletteBitmap = bm_load(filename);
587         if (InterfacePaletteBitmap < 0) {
588                 Error(LOCATION, "Could not load in \"%s\"!", filename);
589         }
590         */
591
592 #ifndef HARDWARE_ONLY
593         palette_use_bm_palette(InterfacePaletteBitmap);
594 #endif
595 }
596
597 // release the interface palette .pcx file, and restore the game palette
598 void common_free_interface_palette()
599 {
600         // unload the interface bitmap from memory
601         if (InterfacePaletteBitmap != -1) {
602                 bm_unload(InterfacePaletteBitmap);
603                 InterfacePaletteBitmap = -1;
604         }
605
606         // restore the normal game palette
607         palette_restore_palette();
608 }
609
610 // Init timers used for flashing buttons
611 void common_flash_button_init()
612 {
613         Flash_timer = timestamp(MSC_FLASH_AFTER_TIME);
614         Flash_toggle = 1;
615         Flash_bright = 0;
616 }
617
618 // determine if we should draw a button as bright
619 int common_flash_bright()
620 {
621         if ( timestamp_elapsed(Flash_timer) ) {
622                 if ( timestamp_elapsed(Flash_toggle) ) {
623                         Flash_toggle = timestamp(MSC_FLASH_INTERVAL);
624                         Flash_bright ^= 1;
625                 }
626         }
627
628         return Flash_bright;
629 }
630
631 // common_select_init() will load in animations and bitmaps that are common to the 
632 // briefing/ship select/weapon select screens.  The global Common_select_inited is set
633 // after this function is called once, and is only cleared when common_select_close()
634 // is called.  This prevents multiple loadings of animations/bitmaps.
635 //
636 // This function also sets the palette based on the file palette01.pcx
637 void common_select_init()
638 {
639         if ( Common_select_inited ) {
640                 nprintf(("Alan","common_select_init() returning without doing anything\n"));
641                 return;
642         }
643
644         nprintf(("Alan","entering common_select_init()\n"));
645
646         // No anims are playing
647         Background_playing = 0;
648         Background_anim = NULL;
649
650         #ifndef DEMO // not for FS2_DEMO
651
652         /*
653         if ( current_detail_level() >= (NUM_DEFAULT_DETAIL_LEVELS-2) ) {
654
655                 anim_play_struct aps;
656
657                 // Load in the background transition anim
658                 if ( Game_mode & GM_MULTIPLAYER )
659                         Background_anim = anim_load("BriefTransMulti", 1);      // 1 as last parm means file is mem-mapped
660                 else  {
661                         Background_anim = anim_load("BriefTrans", 1);   // 1 as last parm means file is mem-mapped
662                 }
663
664                 Assert( Background_anim != NULL );
665                 anim_play_init(&aps, Background_anim, 0, 0);
666                 aps.framerate_independent = 1;
667                 aps.skip_frames = 0;
668                 Background_anim_instance = anim_play(&aps);
669                 Background_playing = 1;         // start playing the Background anim
670         }
671         */
672         Current_screen = Next_screen = ON_BRIEFING_SELECT;
673
674         // load in the icons for the wing slots
675         load_wing_icons(NOX("iconwing01"));
676
677
678         #endif
679
680         Current_screen = Next_screen = ON_BRIEFING_SELECT;
681         
682         Commit_pressed = 0;
683
684         Common_select_inited = 1;
685
686         // this handles the case where the player played a multiplayer game but now is in single player (in one instance
687         // of Freespace)
688         if(!(Game_mode & GM_MULTIPLAYER)){
689                 chatbox_close();
690         }
691
692         // get the value of the team
693         Common_team = 0;                                                        // assume the first team -- we'll change this value if we need to
694         if ( (Game_mode & GM_MULTIPLAYER) && IS_MISSION_MULTI_TEAMS )
695                 Common_team = Net_player->p_info.team;
696
697         ship_select_common_init();      
698         weapon_select_common_init();
699         common_flash_button_init();
700
701         if ( Game_mode & GM_MULTIPLAYER ) {
702                 multi_ts_common_init();
703         }
704
705         // restore loadout from Player_loadout if this is the same mission as the one previously played
706         if ( !(Game_mode & GM_MULTIPLAYER) ) {
707                 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
708                         wss_restore_loadout();
709                         ss_synch_interface();
710                         wl_synch_interface();
711                 }
712         }
713         
714         Drop_icon_mflag = 0;
715         Drop_on_wing_mflag = 0;
716 }
717
718 void common_reset_buttons()
719 {
720         int                     i;
721         UI_BUTTON       *b;
722
723         for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
724                 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
725                 b->reset_status();
726         }
727
728         switch(Current_screen) {
729         case ON_BRIEFING_SELECT:
730                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_REGION].button.skip_first_highlight_callback();
731                 break;
732         case ON_SHIP_SELECT:
733                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_REGION].button.skip_first_highlight_callback();
734                 break;
735         case ON_WEAPON_SELECT:
736                 Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_REGION].button.skip_first_highlight_callback();
737                 break;
738         }
739 }
740
741 // common_select_do() is called once per loop in the interface screens and is used
742 // for drawing and changing the common animations and blitting common bitmaps.
743 int common_select_do(float frametime)
744 {
745         int     k, new_k;
746
747         // If the mouse went up, set flags.  We can't use mouse_up_count() more than once a frame,
748         // since the count gets zeroed after the call.
749         //
750         Drop_icon_mflag = 0;
751         Drop_on_wing_mflag = 0;
752         Brief_mouse_up_flag = 0;
753
754         if ( mouse_up_count(MOUSE_LEFT_BUTTON) ) {
755                 Drop_icon_mflag = 1;
756                 Drop_on_wing_mflag = 1;
757                 Brief_mouse_up_flag = 1;                
758         }
759
760         Mouse_down_last_frame = 0;
761         if ( mouse_down_count(MOUSE_LEFT_BUTTON) ) {
762                 Mouse_down_last_frame = 1;
763         }
764
765         if ( help_overlay_active(BR_OVERLAY) || help_overlay_active(SS_OVERLAY) || help_overlay_active(WL_OVERLAY) ) {
766                 Common_buttons[0][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
767                 Common_buttons[1][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
768                 Common_buttons[2][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
769                 Active_ui_window->set_ignore_gadgets(1);
770         } else {
771                 Active_ui_window->set_ignore_gadgets(0);
772         }
773
774         k = chatbox_process();
775         if ( Game_mode & GM_NORMAL ) {
776                 new_k = Active_ui_window->process(k);
777         } else {
778                 new_k = Active_ui_window->process(k, 0);
779         }
780
781         if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
782                 if ( help_overlay_active(BR_OVERLAY) || help_overlay_active(SS_OVERLAY) || help_overlay_active(WL_OVERLAY) ) {
783                         help_overlay_set_state(BR_OVERLAY, 0);
784                         help_overlay_set_state(SS_OVERLAY, 0);
785                         help_overlay_set_state(WL_OVERLAY, 0);
786                         Active_ui_window->set_ignore_gadgets(0);
787                         k = 0;
788                         new_k = 0;
789                 }
790         }
791
792         // reset timers for flashing buttons if key pressed
793         if ( (k>0) || (new_k>0) ) {
794                 common_flash_button_init();
795         }
796
797         common_music_do();
798
799         /*
800         if ( Background_playing ) {
801
802                 if ( Background_anim_instance->frame_num == BUTTON_SLIDE_IN_FRAME ) {
803                         gamesnd_play_iface(SND_BTN_SLIDE);
804                 }       
805         
806                 if ( Background_anim_instance->frame_num == Background_anim_instance->stop_at ) {
807                         // Free up the big honking background animation, since we won't be playing it again
808                         anim_release_render_instance(Background_anim_instance);
809                         anim_free(Background_anim);
810
811                         Background_playing = 0;         
812                         Current_screen = Next_screen = ON_BRIEFING_SELECT;
813                 }
814         }
815         */
816
817         if ( Current_screen != Next_screen ) {
818                 switch( Next_screen ) {
819                         case ON_BRIEFING_SELECT:
820                                 gameseq_post_event( GS_EVENT_START_BRIEFING );
821                                 break;
822
823                         case ON_SHIP_SELECT:
824                                 // go to the specialized multiplayer team/ship select screen
825                                 if(Game_mode & GM_MULTIPLAYER){
826                                         gameseq_post_event(GS_EVENT_TEAM_SELECT);
827                                 }
828                                 // go to the normal ship select screen
829                                 else {
830                                         gameseq_post_event(GS_EVENT_SHIP_SELECTION);
831                                 }
832                                 break;
833
834                         case ON_WEAPON_SELECT:
835                                 if ( !wss_slots_all_empty() ) {
836                                         gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
837                                 } else {
838                                         common_show_no_ship_error();
839                                 }
840                                 break;
841                 } // end switch
842         }
843
844    return new_k;
845 }
846
847 // -------------------------------------------------------------------------------------
848 // common_render()
849 //
850 void common_render(float frametime)
851 {
852         if ( !Background_playing ) {
853                 gr_set_bitmap(Brief_background_bitmap);
854                 gr_bitmap(0, 0);
855         }
856
857         anim_render_all(0, frametime);
858         anim_render_all(ON_SHIP_SELECT, frametime);
859 }
860
861 // -------------------------------------------------------------------------------------
862 // common_render_selected_screen_button()
863 //
864 //      A very ugly piece of special purpose code.  This is used to draw the pressed button
865 // frame for whatever stage of the briefing/ship select/weapons loadout we are on. 
866 //
867 void common_render_selected_screen_button()
868 {
869         Common_buttons[Next_screen-1][gr_screen.res][Next_screen-1].button.draw_forced(2);
870 }
871
872 // -------------------------------------------------------------------------------------
873 // common_button_do() do the button action for the specified pressed button
874 //
875 void common_button_do(int i)
876 {
877         if ( i == COMMON_COMMIT_BUTTON ) {
878                 Commit_pressed = 1;
879                 return;
880         }
881
882         if ( Background_playing )
883                 return;
884
885         switch ( i ) {
886
887         case COMMON_BRIEFING_BUTTON:
888                 if ( Current_screen != ON_BRIEFING_SELECT ) {
889                         gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
890                         Next_screen = ON_BRIEFING_SELECT;
891                 }
892                 break;
893
894         case COMMON_WEAPON_BUTTON:
895                 if ( Current_screen != ON_WEAPON_SELECT ) {
896                         if ( !wss_slots_all_empty() ) {
897                                 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
898                                 Next_screen = ON_WEAPON_SELECT;
899                         } else {
900                                 common_show_no_ship_error();
901                         }
902                 }
903                 break;
904
905         case COMMON_SS_BUTTON:
906                 if ( Current_screen != ON_SHIP_SELECT ) {
907                         gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
908                         Next_screen = ON_SHIP_SELECT;
909                 }
910                 break;
911
912         case COMMON_OPTIONS_BUTTON:
913                 gamesnd_play_iface(SND_SWITCH_SCREENS);
914                 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
915                 break;
916
917         case COMMON_HELP_BUTTON:
918                 gamesnd_play_iface(SND_HELP_PRESSED);
919                 launch_context_help();
920                 break;
921
922         } // end switch
923 }
924
925 // common_check_keys() will check for keypresses common to all the interface screens.
926 void common_check_keys(int k)
927 {
928         switch (k) {
929
930                 case KEY_ESC: {
931
932                         if ( Current_screen == ON_BRIEFING_SELECT ) {
933                                 if ( brief_get_closeup_icon() != NULL ) {
934                                         brief_turn_off_closeup_icon();
935                                         break;
936                                 }
937                         }
938
939                         // prompt the host of a multiplayer game
940                         if(Game_mode & GM_MULTIPLAYER){
941                                 multi_quit_game(PROMPT_ALL);
942                         }
943                         // go through the single player quit process
944                         else {
945                                 // return to the main menu
946 /*
947                                 int return_to_menu, pf_flags;
948                                 pf_flags = PF_USE_AFFIRMATIVE_ICON|PF_USE_NEGATIVE_ICON;
949                                 return_to_menu = popup(pf_flags, 2, POPUP_NO, POPUP_YES, XSTR( "Do you want to return to the Main Hall?\n(Your campaign position will be saved)", -1));
950                                 if ( return_to_menu == 1 ) {
951                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
952                                 }
953 */
954                                 gameseq_post_event(GS_EVENT_MAIN_MENU);
955                         }                       
956                         break;
957                 }
958
959                 case KEY_CTRLED + KEY_ENTER:
960                         Commit_pressed = 1;
961                         break;
962
963                 case KEY_B:
964                         if ( Current_screen != ON_BRIEFING_SELECT && !Background_playing ) {
965                                 Next_screen = ON_BRIEFING_SELECT;
966                         }
967                         break;
968
969                 case KEY_W:
970                         if ( brief_only_allow_briefing() ) {
971                                 gamesnd_play_iface(SND_GENERAL_FAIL);
972                                 break;
973                         }
974
975                         #ifndef DEMO // not for FS2_DEMO
976                                 if ( Current_screen != ON_WEAPON_SELECT && !Background_playing ) {
977                                         if ( !wss_slots_all_empty() ) {
978                                                 Next_screen = ON_WEAPON_SELECT;
979                                         } else {
980                                                 common_show_no_ship_error();
981                                         }
982                                 }
983                         #else
984                                 gamesnd_play_iface(SND_GENERAL_FAIL);
985                         #endif
986
987                         break;
988
989                 case KEY_S:
990
991                         if ( brief_only_allow_briefing() ) {
992                                 gamesnd_play_iface(SND_GENERAL_FAIL);
993                                 break;
994                         }
995
996                         #ifndef DEMO // not for FS2_DEMO
997                                 if ( Current_screen != ON_SHIP_SELECT && !Background_playing ) {
998                                         Next_screen = ON_SHIP_SELECT;
999                                 }
1000                         #else
1001                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1002                         #endif
1003
1004                         break;
1005
1006                 case KEY_SHIFTED+KEY_TAB:
1007
1008                         if ( brief_only_allow_briefing() ) {
1009                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1010                                 break;
1011                         }
1012
1013                         #ifndef DEMO // not for FS2_DEMO
1014                                 if ( !Background_playing ) {
1015                                         switch ( Current_screen ) {
1016                                                 case ON_BRIEFING_SELECT:
1017                                                         if ( !wss_slots_all_empty() ) {
1018                                                                 Next_screen = ON_WEAPON_SELECT;
1019                                                         } else {
1020                                                                 common_show_no_ship_error();
1021                                                         }
1022                                                         break;
1023
1024                                                 case ON_SHIP_SELECT:
1025                                                         Next_screen = ON_BRIEFING_SELECT;
1026                                                         break;
1027
1028                                                 case ON_WEAPON_SELECT:
1029                                                         Next_screen = ON_SHIP_SELECT;
1030                                                         break;
1031                                                 default:
1032                                                         Int3();
1033                                                         break;
1034                                         }       // end switch
1035                                 }
1036                         #else
1037                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1038                         #endif
1039
1040                         break;
1041
1042                 case KEY_TAB:
1043
1044                         if ( brief_only_allow_briefing() ) {
1045                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1046                                 break;
1047                         }
1048
1049                         #ifndef DEMO // not for FS2_DEMO
1050                                 if ( !Background_playing ) {
1051                                         switch ( Current_screen ) {
1052                                                 case ON_BRIEFING_SELECT:
1053                                                         Next_screen = ON_SHIP_SELECT;
1054                                                         break;
1055
1056                                                 case ON_SHIP_SELECT:
1057                                                         if ( !wss_slots_all_empty() ) {
1058                                                                 Next_screen = ON_WEAPON_SELECT;
1059                                                         } else {
1060                                                                 common_show_no_ship_error();
1061                                                         }
1062                                                         break;
1063
1064                                                 case ON_WEAPON_SELECT:
1065                                                         Next_screen = ON_BRIEFING_SELECT;
1066                                                         break;
1067                                                 default:
1068                                                         Int3();
1069                                                         break;
1070                                         }       // end switch
1071                                 }
1072                         #else
1073                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1074                         #endif
1075
1076                         break;
1077
1078                 case KEY_P:
1079                         if ( Anim_paused )
1080                                 Anim_paused = 0;
1081                         else
1082                                 Anim_paused = 1;
1083                         break;
1084         } // end switch
1085 }
1086
1087 // common_select_close() will release the memory for animations and bitmaps that
1088 // were loaded in common_select_init().  This function will abort if the Common_select_inited
1089 // flag is not set.  The last thing common_select_close() does in clear the Common_select_inited
1090 // flag.  
1091 //
1092 // weapon_select_close() and ship_select_close() are both called, since common_select_close()
1093 // is the function that is called the interface screens are finally exited.
1094 void common_select_close()
1095 {
1096         if ( !Common_select_inited ) {
1097                 nprintf(("Alan","common_select_close() returning without doing anything\n"));
1098                 return;
1099         }
1100
1101         nprintf(("Alan","entering common_select_close()\n"));
1102         
1103         weapon_select_close();
1104         if(Game_mode & GM_MULTIPLAYER){
1105                 multi_ts_close();
1106         } 
1107         ship_select_close();    
1108         brief_close();  
1109
1110         common_free_interface_palette();
1111
1112         // release the bitmpas that were previously extracted from anim files
1113         unload_wing_icons();
1114
1115         // Release any instances that may still exist
1116         anim_release_all_instances();
1117
1118         // free the anim's that were loaded into memory
1119         /*
1120         if ( Background_anim ) {
1121                 anim_free(Background_anim);
1122                 Background_anim = NULL;
1123         }
1124         */
1125
1126         common_music_close();
1127         Common_select_inited = 0;
1128 }
1129
1130 // ------------------------------------------------------------------------
1131 //      load_wing_icons() creates the bitmaps for wing icons 
1132 //
1133 void load_wing_icons(char *filename)
1134 {
1135         int first_frame, num_frames;
1136
1137         first_frame = bm_load_animation(filename, &num_frames);
1138         if ( first_frame == -1 ) {
1139                 Error(LOCATION, "Could not load icons from %s\n", filename);
1140                 return;
1141         }
1142
1143         Wing_slot_disabled_bitmap = first_frame;
1144         Wing_slot_empty_bitmap = first_frame + 1;
1145 //      Wing_slot_player_empty_bitmap = first_frame + 2;
1146 }
1147
1148 // ------------------------------------------------------------------------
1149 //      common_scroll_up_pressed()
1150 //
1151 int common_scroll_up_pressed(int *start, int size, int max_show)
1152 {
1153         // check if we even need to scroll at all
1154         if ( size <= max_show ) {
1155                 return 0;
1156         }
1157
1158         if ( (size - *start) > max_show ) {
1159                 *start += 1;
1160                 return 1;
1161         }
1162         return 0;
1163 }
1164
1165 // ------------------------------------------------------------------------
1166 //      common_scroll_down_pressed()
1167 //
1168 int common_scroll_down_pressed(int *start, int size, int max_show)
1169 {
1170         // check if we even need to scroll at all
1171         if ( size <= max_show ) {
1172                 return 0;
1173         }
1174
1175         if ( *start > 0 ) {
1176                 *start -= 1;
1177                 return 1;
1178         }
1179         return 0;
1180 }
1181
1182 // NEWSTUFF BEGIN
1183
1184 loadout_data Player_loadout;    // what the ship and weapon loadout is... used since we want to use the 
1185                                                                                 // same loadout if the mission is played again
1186
1187 //wss_unit      Wss_slots[MAX_WSS_SLOTS];                               // slot data struct
1188 //int           Wl_pool[MAX_WEAPON_TYPES];                              // weapon pool 
1189 //int           Ss_pool[MAX_SHIP_TYPES];                                // ship pool
1190 //int           Wss_num_wings;                                                          // number of player wings
1191
1192 wss_unit        Wss_slots_teams[MAX_TEAMS][MAX_WSS_SLOTS];
1193 int             Wl_pool_teams[MAX_TEAMS][MAX_WEAPON_TYPES];
1194 int             Ss_pool_teams[MAX_TEAMS][MAX_SHIP_TYPES];
1195 int             Wss_num_wings_teams[MAX_TEAMS];
1196
1197 wss_unit        *Wss_slots;
1198 int             *Wl_pool;
1199 int             *Ss_pool;
1200 int             Wss_num_wings;
1201
1202 // save ship selection loadout to the Player_loadout struct
1203 void wss_save_loadout()
1204 {
1205         int i,j;
1206
1207         // save the ship pool
1208         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1209                 Player_loadout.ship_pool[i] = Ss_pool[i]; 
1210         }
1211
1212         // save the weapons pool
1213         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1214                 Player_loadout.weapon_pool[i] = Wl_pool[i]; 
1215         }
1216
1217         // save the ship class / weapons for each slot
1218         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1219                 Player_loadout.unit_data[i].ship_class = Wss_slots[i].ship_class;
1220
1221                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
1222                         Player_loadout.unit_data[i].wep[j] = Wss_slots[i].wep[j];
1223                         Player_loadout.unit_data[i].wep_count[j] = Wss_slots[i].wep_count[j];
1224                 }
1225         }
1226 }
1227
1228 // restore ship/weapons loadout from the Player_loadout struct
1229 void wss_restore_loadout()
1230 {
1231         int i,j;
1232         wss_unit        *slot;
1233
1234         // only restore if mission hasn't changed
1235         if ( stricmp(Player_loadout.last_modified, The_mission.modified) ) {
1236                 return;
1237         }
1238
1239         // restore the ship pool
1240         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1241                 Ss_pool[i] = Player_loadout.ship_pool[i]; 
1242         }
1243
1244         // restore the weapons pool
1245         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1246                 Wl_pool[i] = Player_loadout.weapon_pool[i]; 
1247         }
1248
1249         // restore the ship class / weapons for each slot
1250         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1251                 slot = &Player_loadout.unit_data[i];
1252                 Wss_slots[i].ship_class = slot->ship_class;
1253
1254                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
1255                         Wss_slots[i].wep[j]= slot->wep[j];
1256                         Wss_slots[i].wep_count[j] = slot->wep_count[j];
1257                 }
1258         }
1259 }
1260
1261 // Do a direct restore of the Player_loadout ship/weapon data to the wings
1262 void wss_direct_restore_loadout()
1263 {
1264         int                             i, j;
1265         wing                            *wp;
1266         wss_unit                        *slot;
1267
1268         // only restore if mission hasn't changed
1269         if ( stricmp(Player_loadout.last_modified, The_mission.modified) ) {
1270                 return;
1271         }
1272
1273         for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
1274
1275                 if ( Starting_wings[i] < 0 )
1276                         continue;
1277
1278                 wp = &Wings[Starting_wings[i]];
1279
1280                 // If this wing is still on the arrival list, then update the parse objects
1281                 if ( wp->ship_index[0] == -1 ) {
1282                         p_object *p_objp;
1283                         j=0;
1284                         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
1285                                 slot = &Player_loadout.unit_data[i*4+j];
1286                                 if ( p_objp->wingnum == WING_INDEX(wp) ) {
1287                                         p_objp->ship_class = slot->ship_class;
1288                                         wl_update_parse_object_weapons(p_objp, slot);
1289                                         j++;
1290                                 }
1291                         }
1292                 } else {
1293                         int     k;
1294                         int cleanup_ship_index[MAX_WING_SLOTS];
1295                         ship    *shipp;
1296
1297                         for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
1298                                 cleanup_ship_index[k] = -1;
1299                         }
1300
1301                         // This wing is already created, so directly update the ships
1302                         for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
1303                                 slot = &Player_loadout.unit_data[i*4+j];
1304                                 shipp = &Ships[wp->ship_index[j]];
1305                                 if ( shipp->ship_info_index != slot->ship_class ) {
1306
1307                                         if ( wp->ship_index[j] == -1 ) {
1308                                                 continue;
1309                                         }
1310
1311                                         if ( slot->ship_class == -1 ) {
1312                                                 cleanup_ship_index[j] = wp->ship_index[j];
1313                                                 ship_add_exited_ship( shipp, SEF_PLAYER_DELETED );
1314                                                 obj_delete(shipp->objnum);
1315                                                 hud_set_wingman_status_none( shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
1316                                                 continue;
1317                                         } else {
1318                                                 change_ship_type(wp->ship_index[j], slot->ship_class);
1319                                         }
1320                                 }
1321                                 wl_bash_ship_weapons(&Ships[wp->ship_index[j]].weapons, slot);
1322                         }
1323
1324                         for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
1325                                 if ( cleanup_ship_index[k] != -1 ) {
1326                                         ship_wing_cleanup( cleanup_ship_index[k], wp );
1327                                 }
1328                         }
1329
1330                 }
1331         } // end for 
1332 }
1333 int wss_slots_all_empty()
1334 {
1335         int i;
1336
1337         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1338                 if ( Wss_slots[i].ship_class >= 0 ) 
1339                         break;
1340         }
1341
1342         if ( i == MAX_WSS_SLOTS )
1343                 return 1;
1344         else
1345                 return 0;
1346 }
1347
1348 // determine the mode (WSS_...) based on slot/list index values
1349 int wss_get_mode(int from_slot, int from_list, int to_slot, int to_list, int wl_ship_slot)
1350 {
1351         int mode, to_slot_empty=0;
1352
1353         if ( wl_ship_slot >= 0 ) {
1354                 // weapons loadout
1355                 if ( to_slot >= 0 ) {
1356                         if ( Wss_slots[wl_ship_slot].wep_count[to_slot] == 0 ) {
1357                                 to_slot_empty = 1;
1358                         }
1359                 }
1360         } else {
1361                 // ship select
1362                 if ( to_slot >= 0 ) {
1363                         if ( Wss_slots[to_slot].ship_class == -1 ){
1364                                 to_slot_empty = 1;
1365                         }
1366                 }
1367         }
1368
1369         // determine mode
1370         if ( from_slot >= 0 && to_slot >= 0 ) {
1371                 mode = WSS_SWAP_SLOT_SLOT;
1372         } else if ( from_slot >= 0 && to_list >= 0 ) {
1373                 mode = WSS_DUMP_TO_LIST;
1374         } else if ( (from_list >= 0) && (to_slot >= 0) && (to_slot_empty) ) {
1375                 mode = WSS_GRAB_FROM_LIST;
1376         } else if ( (from_list >= 0) && (to_slot >= 0) && (!to_slot_empty) ) {
1377                 mode = WSS_SWAP_LIST_SLOT;
1378         } else {
1379                 mode = -1;      // no changes required
1380         }
1381
1382         return mode;
1383 }
1384
1385 // store all the unit data and pool data 
1386 int store_wss_data(ubyte *block, int max_size, int sound,int player_index)
1387 {
1388         int j, i,offset=0;      
1389         short player_id;        
1390         short ishort;
1391
1392         // write the ship pool 
1393         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1394                 if ( Ss_pool[i] > 0 ) { 
1395                         block[offset++] = (ubyte)i;
1396                         Assert( Ss_pool[i] < UCHAR_MAX );
1397                         
1398                         // take care of sign issues
1399                         if(Ss_pool[i] == -1){
1400                                 block[offset++] = 0xff;
1401                         } else {
1402                                 block[offset++] = (ubyte)Ss_pool[i];
1403                         }
1404                 }
1405         }
1406
1407         block[offset++] = 0xff; // signals start of weapons pool
1408
1409         // write the weapon pool
1410         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1411                 if ( Wl_pool[i] > 0 ) {
1412                         block[offset++] = (ubyte)i;
1413                         ishort = (short)Wl_pool[i];
1414                         memcpy(block+offset, &ishort, sizeof(short));
1415                         offset += sizeof(short);
1416                 }
1417         }
1418
1419         // write the unit data
1420
1421         block[offset++] = 0xff; // signals start of unit data
1422
1423         for ( i=0; i<MAX_WSS_SLOTS; i++ ) {
1424                 Assert( Wss_slots[i].ship_class < UCHAR_MAX );
1425                 if(Wss_slots[i].ship_class == -1){
1426                         block[offset++] = 0xff;
1427                 } else {
1428                         block[offset++] = (ubyte)(Wss_slots[i].ship_class);
1429                 }
1430                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
1431                         // take care of sign issues
1432                         Assert( Wss_slots[i].wep[j] < UCHAR_MAX );                      
1433                         if(Wss_slots[i].wep[j] == -1){
1434                                 block[offset++] = 0xff;
1435                         } else {
1436                                 block[offset++] = (ubyte)(Wss_slots[i].wep[j]);
1437                         }
1438
1439                         Assert( Wss_slots[i].wep_count[j] < SHRT_MAX );
1440                         ishort = short(Wss_slots[i].wep_count[j]);
1441
1442                         memcpy(&(block[offset]), &(ishort), sizeof(short) );
1443                         offset += sizeof(short);
1444                 }
1445
1446                 // mwa -- old way below -- too much space
1447                 //memcpy(block+offset, &Wss_slots[i], sizeof(wss_unit));
1448                 //offset += sizeof(wss_unit);
1449         }
1450
1451         // any sound index
1452         if(sound == -1){
1453                 block[offset++] = 0xff;
1454         } else {
1455                 block[offset++] = (ubyte)sound;
1456         }
1457
1458         // add a netplayer address to identify who should play the sound
1459         player_id = -1;
1460         if(player_index != -1){
1461                 player_id = Net_players[player_index].player_id;                
1462         }
1463         memcpy(block+offset,&player_id,sizeof(player_id));
1464         offset += sizeof(player_id);
1465
1466         Assert( offset < max_size );
1467         return offset;
1468 }
1469
1470 int restore_wss_data(ubyte *block)
1471 {
1472         int     i, j, sanity, offset=0;
1473         ubyte   b1, b2,sound;   
1474         short ishort;
1475         short player_id;        
1476
1477         // restore ship pool
1478         sanity=0;
1479         memset(Ss_pool, 0, MAX_SHIP_TYPES*sizeof(int));
1480         for (;;) {
1481                 if ( sanity++ > MAX_SHIP_TYPES ) {
1482                         Int3();
1483                         break;
1484                 }
1485
1486                 b1 = block[offset++];
1487                 if ( b1 == 0xff ) {
1488                         break;
1489                 }
1490         
1491                 // take care of sign issues
1492                 b2 = block[offset++];
1493                 if(b2 == 0xff){
1494                         Ss_pool[b1] = -1;
1495                 } else {
1496                         Ss_pool[b1] = b2;
1497                 }
1498         }
1499
1500         // restore weapons pool
1501         sanity=0;
1502         memset(Wl_pool, 0, MAX_WEAPON_TYPES*sizeof(int));
1503         for (;;) {
1504                 if ( sanity++ > MAX_WEAPON_TYPES ) {
1505                         Int3();
1506                         break;
1507                 }
1508
1509                 b1 = block[offset++];
1510                 if ( b1 == 0xff ) {
1511                         break;
1512                 }
1513         
1514                 memcpy(&ishort, block+offset, sizeof(short));
1515                 offset += sizeof(short);
1516                 Wl_pool[b1] = ishort;
1517         }
1518
1519         for ( i=0; i<MAX_WSS_SLOTS; i++ ) {
1520                 if(block[offset] == 0xff){
1521                         Wss_slots[i].ship_class = -1;
1522                 } else {
1523                         Wss_slots[i].ship_class = block[offset];
1524                 }
1525                 offset++;               
1526                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
1527                         // take care of sign issues
1528                         if(block[offset] == 0xff){
1529                                 Wss_slots[i].wep[j] = -1;
1530                                 offset++;
1531                         } else {
1532                                 Wss_slots[i].wep[j] = (int)(block[offset++]);
1533                         }
1534                 
1535                         memcpy( &ishort, &(block[offset]), sizeof(short) );
1536                         Wss_slots[i].wep_count[j] = (int)ishort;
1537                         offset += sizeof(short);
1538                 }
1539
1540                 // mwa -- old way below
1541                 //memcpy(&Wss_slots[i], block+offset, sizeof(wss_unit));
1542                 //offset += sizeof(wss_unit);
1543         }
1544
1545         // read in the sound data
1546         sound = block[offset++];                                        // the sound index
1547
1548         // read in the player address
1549         memcpy(&player_id,block+offset,sizeof(player_id));
1550         offset += sizeof(short);
1551         
1552         // determine if I'm the guy who should be playing the sound
1553         if((Net_player != NULL) && (Net_player->player_id == player_id)){
1554                 // play the sound
1555                 if(sound != 0xff){
1556                         gamesnd_play_iface((int)sound);
1557                 }
1558         }
1559
1560         if(!(Game_mode & GM_MULTIPLAYER)){
1561                 ss_synch_interface();
1562         }       
1563         return offset;
1564 }
1565
1566 // NEWSTUFF END