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