]> icculus.org git repositories - taylor/freespace2.git/blob - src/missionui/missionweaponchoice.cpp
silence compiler warnings (mostly shadow variables)
[taylor/freespace2.git] / src / missionui / missionweaponchoice.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/MissionUI/MissionWeaponChoice.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for the weapon loadout screen
16  *
17  * $Log$
18  * Revision 1.8  2005/03/29 02:18:47  taylor
19  * Various 64-bit platform fixes
20  * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
21  * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
22  * Streaming audio support (big thanks to Pierre Willenbrock!!)
23  * Removed dependance on strings.tbl for FS1 since we don't actually need it now
24  *
25  * Revision 1.7  2004/09/20 01:31:44  theoddone33
26  * GCC 3.4 fixes.
27  *
28  * Revision 1.6  2003/06/11 18:30:33  taylor
29  * plug memory leaks
30  *
31  * Revision 1.5  2003/05/25 02:30:43  taylor
32  * Freespace 1 support
33  *
34  * Revision 1.4  2002/06/16 01:43:23  relnev
35  * fixed demo dogfight multiplayer mission
36  *
37  * minor sound changes
38  *
39  * Revision 1.3  2002/06/09 04:41:23  relnev
40  * added copyright header
41  *
42  * Revision 1.2  2002/05/07 03:16:46  theoddone33
43  * The Great Newline Fix
44  *
45  * Revision 1.1.1.1  2002/05/03 03:28:10  root
46  * Initial import.
47  *
48  * 
49  * 40    11/01/99 11:22a Jefff
50  * some weapon name translations
51  * 
52  * 39    9/10/99 10:26a Jefff
53  * default weapon anim selection fix
54  * 
55  * 38    9/06/99 3:30p Mikek
56  * Added system for restricting weapon choices based on ship class for
57  * dogfight missions.
58  * 
59  * 37    8/27/99 11:59a Jefff
60  * fixed unnecessary sound playing
61  * 
62  * 36    8/05/99 3:40p Jefff
63  * hi-res text adjustments
64  * 
65  * 35    8/05/99 11:32a Jefff
66  * fixed hi-res weapon anims not loading from packfile
67  * 
68  * 34    7/30/99 4:35p Andsager
69  * Clean up change ship sound
70  * 
71  * 33    7/30/99 4:22p Andsager
72  * restored ship and weapon anim sounds for demo.  Added sound for
73  * changing ship in weapon loadout screen.
74  * 
75  * 32    7/27/99 7:34p Jefff
76  * Lotsa clean up, moving stuff around, generally making the whole damn
77  * thing work right.
78  * 
79  * 31    7/27/99 3:01p Jefff
80  * crippled wl_start_slot_animation to prevent loading of overhead ship
81  * .anis.  also began modifications for multiplayer interface.
82  * 
83  * 30    7/25/99 5:49p Jefff
84  * initial weapon ani is now one of the ship's weapons.  this will fall
85  * back to the original search if the ship should be weaponless.
86  * 
87  * 29    7/24/99 6:03p Jefff
88  * Added "lock" text to multiplayer lock button
89  * 
90  * 28    7/21/99 6:02p Jefff
91  * fixed weapon counts running into weapon icons
92  * 
93  * 27    7/21/99 3:24p Andsager
94  * Modify demo to use 2 frame ship and weapon select anis and cut sounds
95  * associated with ani
96  * 
97  * 26    7/20/99 7:07p Jefff
98  * added "reset" text above reset button
99  * 
100  * 25    7/20/99 1:48p Jefff
101  * Long weapon titles now wrap to next line
102  * 
103  * 24    7/20/99 10:44a Jefff
104  * increased WEAPON_DESC_MAX_LINES to 6
105  * 
106  * 23    7/20/99 12:26a Jefff
107  * text wipe sound FX
108  * 
109  * 22    7/19/99 5:08p Jefff
110  * Added text descriptions for selected weapons, complete with wipe
111  * effect.
112  * 
113  * 21    7/16/99 1:50p Dave
114  * 8 bit aabitmaps. yay.
115  * 
116  * 20    7/15/99 9:20a Andsager
117  * FS2_DEMO initial checkin
118  * 
119  * 19    7/11/99 3:20p Kellys
120  * Make sure we load high-res weapon rotations in 1024
121  * 
122  * 18    7/09/99 5:54p Dave
123  * Seperated cruiser types into individual types. Added tons of new
124  * briefing icons. Campaign screen.
125  * 
126  * 17    7/09/99 12:21a Dave
127  * Change weapon loop anim frame.
128  * 
129  * 16    3/25/99 2:45p Neilk
130  * Fixed lock button
131  * 
132  * 15    3/23/99 9:23p Neilk
133  * fixed various multiplayer lock button problems
134  * 
135  * 14    3/10/99 6:21p Neilk
136  * Added new artwork for hires
137  * 
138  * 13    2/21/99 6:01p Dave
139  * Fixed standalone WSS packets. 
140  * 
141  * 12    2/18/99 11:46a Neilk
142  * hires interface coord support
143  * 
144  * 11    2/11/99 3:08p Dave
145  * PXO refresh button. Very preliminary squad war support.
146  * 
147  * 10    2/01/99 5:55p Dave
148  * Removed the idea of explicit bitmaps for buttons. Fixed text
149  * highlighting for disabled gadgets.
150  * 
151  * 9     1/30/99 1:29a Dave
152  * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
153  * screen.  Fixed beam weapon death messages.
154  * 
155  * 8     1/29/99 4:17p Dave
156  * New interface screens.
157  * 
158  * 7     1/27/99 9:56a Dave
159  * Temporary checkin of beam weapons for Dan to make cool sounds.
160  * 
161  * 6     12/18/98 1:13a Dave
162  * Rough 1024x768 support for Direct3D. Proper detection and usage through
163  * the launcher.
164  * 
165  * 5     11/30/98 1:07p Dave
166  * 16 bit conversion, first run.
167  * 
168  * 4     11/17/98 11:12a Dave
169  * Removed player identification by address. Now assign explicit id #'s.
170  * 
171  * 3     10/13/98 9:29a Dave
172  * Started neatening up freespace.h. Many variables renamed and
173  * reorganized. Added AlphaColors.[h,cpp]
174  * 
175  * 2     10/07/98 10:53a Dave
176  * Initial checkin.
177  * 
178  * 1     10/07/98 10:50a Dave
179  * 
180  * 119   6/17/98 11:06a Lawrance
181  * put in weapon description tooltip
182  * 
183  * 118   6/13/98 6:01p Hoffoss
184  * Externalized all new (or forgot to be added) strings to all the code.
185  * 
186  * 117   6/01/98 11:43a John
187  * JAS & MK:  Classified all strings for localization.
188  * 
189  * 116   5/19/98 8:35p Dave
190  * Revamp PXO channel listing system. Send campaign goals/events to
191  * clients for evaluation. Made lock button pressable on all screens. 
192  * 
193  * 115   5/18/98 2:49p Lawrance
194  * Put in weapon animation sound hook
195  * 
196  * 114   5/08/98 7:52p Lawrance
197  * Add code to loop new weapon animations
198  * 
199  * 113   5/06/98 11:50p Lawrance
200  * Clean up help overlay code for loadout screens
201  * 
202  * 112   5/04/98 5:27p Johnson
203  * Fixed a team vs. team weapons loadout bug.
204  * 
205  * 111   5/03/98 1:55a Lawrance
206  * Fix some sound problems with loadout screens
207  * 
208  * 110   4/30/98 6:03p Lawrance
209  * Make drag and drop work better.
210  * 
211  * 109   4/27/98 6:02p Dave
212  * Modify how missile scoring works. Fixed a team select ui bug. Speed up
213  * multi_lag system. Put in new main hall.
214  * 
215  * 108   4/24/98 2:17a Lawrance
216  * repositioin ship name in weapons loadout
217  * 
218  * 107   4/22/98 7:24p Dave
219  * Made sure the "player/ships" locked button for multiplayer appears on
220  * all briefing screens.
221  * 
222  * 106   4/21/98 6:45p Dave
223  * AL: Fix bug with replacement weapons on ships
224  * 
225  * 105   4/17/98 5:27p Dave
226  * More work on the multi options screen. Fixed many minor ui todo bugs.
227  * 
228  * 104   4/16/98 8:05p Lawrance
229  * fix some bugs with numbers over-writing weapon icons
230  * 
231  * 103   4/10/98 4:51p Hoffoss
232  * Made several changes related to tooltips.
233  * 
234  * 102   4/08/98 1:18a Lawrance
235  * Fix bug that could occur when picking alternate weapons (ie count could
236  * have been wrong due to missile size)
237  * 
238  * 101   4/07/98 5:42p Dave
239  * Put in support for ui display of voice system status (recording,
240  * playing back, etc). Make sure main hall music is stopped before
241  * entering a multiplayer game via ingame join.
242  * 
243  * 100   4/02/98 11:40a Lawrance
244  * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
245  * 
246  * 99    3/31/98 1:50p Duncan
247  * ALAN: fix bugs with selecting alternate weapons 
248  * 
249  * 98    3/30/98 12:18a Lawrance
250  * change some DEMO_RELEASE code to not compile code rather than return
251  * early
252  * 
253  * 97    3/29/98 1:24p Dave
254  * Make chatbox not clear between multiplayer screens. Select player ship
255  * as default in mp team select and weapons select screens. Made create
256  * game mission list use 2 fixed size columns.
257  * 
258  * 96    3/29/98 12:55a Lawrance
259  * Get demo build working with limited set of data.
260  * 
261  * 95    3/26/98 5:47p Lawrance
262  * Implement default weapon picking if default weapons not available in
263  * pool
264  * 
265  * 94    3/25/98 8:43p Hoffoss
266  * Changed anim_play() to not be so damn complex when you try and call it.
267  * 
268  * 93    3/25/98 11:23a Mike
269  * Fix stack overwrite due to async between MAX_SECONDARY_WEAPONS and
270  * MAX_WL_SECONDARY.
271  * 
272  * 92    3/21/98 2:47p Dave
273  * Fixed chat packet routing problem on standalone. Fixed wss_request
274  * packet routing on standalone.
275  * 
276  * 91    3/19/98 5:34p Lawrance
277  * Tweak drag/drop behavior in weapons loadout
278  * 
279  * 90    3/14/98 2:48p Dave
280  * Cleaned up observer joining code. Put in support for file xfers to
281  * ingame joiners (observers or not). Revamped and reinstalled pseudo
282  * lag/loss system.
283  * 
284  * 89    3/12/98 4:03p Lawrance
285  * don't press buttons when icon dropped on them
286  * 
287  * 88    3/10/98 1:35p Lawrance
288  * Fix default selected weapon bug
289  * 
290  * 87    3/09/98 9:55p Lawrance
291  * Move secondary icons to the right to avoid overlap with numbers
292  * 
293  * 86    3/09/98 11:13a Lawrance
294  * Fix up drop sound effects used in loadout screens.
295  * 
296  * 85    3/06/98 5:36p Dave
297  * Finished up first rev of team vs team. Probably needs to be debugged
298  * thoroughly.
299  * 
300  * 84    3/05/98 5:03p Dave
301  * More work on team vs. team support for multiplayer. Need to fix bugs in
302  * weapon select.
303  * 
304  * 83    3/01/98 3:26p Dave
305  * Fixed a few team select bugs. Put in multiplayer intertface sounds.
306  * Corrected how ships are disabled/enabled in team select/weapon select
307  * screens.
308  * 
309  * 82    2/28/98 7:04p Lawrance
310  * Don't show reset button in multiplayer
311  * 
312  * 81    2/27/98 11:32a Andsager
313  * AL: Fix bug with showing valid weapon slots for ships that arrive late.
314  * 
315  * 80    2/26/98 4:59p Allender
316  * groundwork for team vs team briefings.  Moved weaponry pool into the
317  * Team_data structure.  Added team field into the p_info structure.
318  * Allow for mutliple structures in the briefing code.
319  * 
320  * 79    2/24/98 6:21p Lawrance
321  * Integrate new reset button into loadout screens
322  * 
323  * 78    2/22/98 4:17p John
324  * More string externalization classification... 190 left to go!
325  * 
326  * 77    2/22/98 12:19p John
327  * Externalized some strings
328  * 
329  * 76    2/19/98 6:26p Dave
330  * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
331  * initial support for player data uploading.
332  * 
333  * 75    2/18/98 10:37p Dave
334  * Fixed a mp team select bug which allowed players to commit at
335  * inappropriate times.
336  * 
337  * 74    2/18/98 3:56p Dave
338  * Several bugs fixed for mp team select screen. Put in standalone packet
339  * routing for team select.
340  * 
341  * 73    2/16/98 10:27a Lawrance
342  * Fix bug in wl_cull_illegal_weapons()
343  * 
344  * 72    2/15/98 11:28p Allender
345  * allow increase in MAX_WEAPON_TYPES by chaning all bitfield references
346  * 
347  * 71    2/13/98 5:15p Lawrance
348  * Fix help overlay bug in weapons loadout.
349  * 
350  * 70    2/13/98 3:46p Dave
351  * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
352  * functions.
353  * 
354  * 69    2/09/98 11:24p Lawrance
355  * Allow player to click on disallowed weapons, but don't let them drag
356  * them away from the list.
357  * 
358  * 68    2/07/98 5:47p Lawrance
359  * reset flashing if a button gets highlighted
360  * 
361  * 67    2/06/98 5:15p Jasen
362  * AL: Allow up to 10000 of any given missile in the pool
363  * 
364  * 66    2/05/98 11:21p Lawrance
365  * When flashing buttons, use highlight frame
366  * 
367  * 65    2/02/98 3:36p Jasen
368  * AL: remove weapon debug name, and allow for 2 frame weapon anis
369  * 
370  * 64    2/02/98 3:21p Jasen
371  * Updated coords for weapon anim location.
372  * 
373  * 63    1/20/98 5:52p Lawrance
374  * account for no player ship when moving to weapons loadout
375  * 
376  * 62    1/20/98 2:23p Dave
377  * Removed optimized build warnings. 99% done with ingame join fixes.
378  * 
379  * 61    1/20/98 11:08a Lawrance
380  * Fix sound error when clicking on a weapon.
381  * 
382  * 60    1/19/98 2:17p Lawrance
383  * Fix bug that was not recognizing non-default weapons on late-arriving
384  * wings.
385  * 
386  * 59    1/15/98 4:09p Lawrance
387  * fix weapon scrolling bug
388  * 
389  * 58    1/14/98 6:44p Lawrance
390  * Take out unnecessary instance checking when freeing anims.
391  * 
392  * 57    1/12/98 5:17p Dave
393  * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
394  * work through the standalone.
395  * 
396  * 56    1/10/98 12:47a Lawrance
397  * update some comments
398  * 
399  * 55    1/09/98 6:06p Dave
400  * Put in network sound support for multiplayer ship/weapon select
401  * screens. Made clients exit game correctly through warp effect. Fixed
402  * main hall menu help overlay bug.
403  * 
404  * 54    1/09/98 4:08p John
405  * Fixed a bug loading too many icon frames
406  * 
407  * 53    1/08/98 10:55p Lawrance
408  * Fix bug where forbidden weapons were not updated when a ship was
409  * changed before weapons loadout is entered.
410  * 
411  * 52    1/08/98 5:19p Sandeep
412  * Alan made a change which fixed missions with more than 4 types of
413  * secondary weapons.
414  * 
415  * 51    1/08/98 11:38a Lawrance
416  * correct typo
417  * 
418  * 50    1/08/98 11:36a Lawrance
419  * Get ship select and weapons loadout icon dropping sound effects working
420  * for single and multiplayer
421  * 
422  * 49    1/02/98 9:10p Lawrance
423  * Big changes to how colors get set on the HUD.
424  * 
425  * 48    12/30/97 6:08p Lawrance
426  * Fix bug where player discarded ship before entering weapon select
427  * 
428  * 47    12/29/97 4:21p Lawrance
429  * Flash buttons on briefing/ship select/weapons loadout when enough time
430  * has elapsed without activity.
431  * 
432  * 46    12/29/97 10:11a Lawrance
433  * Don't play drop sound when a weapon is clicked on in a slot.
434  * 
435  * 45    12/24/97 8:54p Lawrance
436  * Integrating new popup code
437  * 
438  * 44    12/24/97 1:19p Lawrance
439  * fix some bugs with the multiplayer ship/weapons loadout
440  * 
441  * 43    12/23/97 5:25p Allender
442  * more fixes to multiplayer ship selection.  Fixed strange reentrant
443  * problem with cf_callback when loading freespace data
444  * 
445  * 42    12/23/97 11:59a Allender
446  * changes to ship/wespon selection for multplayer.  added sounds to some
447  * interface screens.  Update and modiied end-of-briefing packets -- yet
448  * to be tested.
449  * 
450  * 41    12/23/97 11:48a Lawrance
451  * fix bug that could cause assert when swapping secondary weapons
452  * 
453  * 40    12/22/97 6:18p Lawrance
454  * Get save/restore of player loadout working with new code
455  * 
456  * 39    12/22/97 1:40a Lawrance
457  * Re-write ship select/weapons loadout to be multiplayer friendly
458  * 
459  * 38    12/19/97 1:23p Dave
460  * Put in multiplayer groundwork for new weapon/ship select screens.
461  * 
462  * 37    12/19/97 12:44p Dave
463  * Put in final touches on ship/weapon select. However, this is all going
464  * to be rewritten.
465  * 
466  * $NoKeywords: $
467  */
468
469 #include "missionscreencommon.h"
470 #include "missionweaponchoice.h"
471 #include "missionshipchoice.h"
472 #include "timer.h"
473 #include "key.h"
474 #include "mouse.h"
475 #include "bmpman.h"
476 #include "2d.h"
477 #include "snazzyui.h"
478 #include "animplay.h"
479 #include "freespace.h"
480 #include "gamesequence.h"
481 #include "multi.h"
482 #include "missionbrief.h"
483 #include "ui.h"
484 #include "gamesnd.h"
485 #include "animplay.h"
486 #include "contexthelp.h"
487 #include "chatbox.h"
488 #include "linklist.h"
489 #include "multimsgs.h"
490 #include "popup.h"
491 #include "multiteamselect.h"
492 #include "multiui.h"
493 #include "alphacolors.h"
494 #include "localize.h"
495
496 //#define MAX_PRIMARY_BANKS             3
497 //#define MAX_SECONDARY_BANKS   3       //      Lowered from 5 to 3 by MK on 3/25/98.  This needs to be <= MAX_WL_SECONDARY or you'll get stack overwrites.
498
499 #define IS_BANK_PRIMARY(x)                      (x<3?1:0)
500 #define IS_BANK_SECONDARY(x)            (x>2?1:0)
501
502 #define IS_LIST_PRIMARY(x)                      (Weapon_info[x].subtype==WP_MISSILE?0:1)
503 #define IS_LIST_SECONDARY(x)            (Weapon_info[x].subtype==WP_MISSILE?1:0)
504
505 //XSTR:OFF
506 #if (MAX_PRIMARY_BANKS > MAX_WL_PRIMARY)
507 #error "Illegal: MAX_PRIMARY_BANKS greater than MAX_WL_PRIMARY"
508 #endif
509
510 #if (MAX_SECONDARY_BANKS > MAX_WL_SECONDARY)
511 #error "Illegal: MAX_SECONDARY_BANKS greater than MAX_WL_SECONDARY"
512 #endif
513 //XSTR:ON
514
515 //////////////////////////////////////////////////////////////////
516 // Game-wide globals
517 //////////////////////////////////////////////////////////////////
518
519 // This game-wide global flag is set to 1 to indicate that the weapon
520 // select screen has been opened and memory allocated.  This flag
521 // is needed so we can know if weapon_select_close() needs to called if
522 // restoring a game from the Options screen invoked from weapon select
523 int Weapon_select_open = 0;
524
525 //////////////////////////////////////////////////////////////////
526 // UI Data
527 //////////////////////////////////////////////////////////////////
528
529 typedef struct wl_bitmap_group
530 {
531         int first_frame;
532         int num_frames;
533 } wl_bitmap_group;
534
535 #if defined(FS2_DEMO) || defined(FS1_DEMO)
536 #define WEAPON_ANIM_LOOP_FRAME                          1
537 #elif MAKE_FS1
538 #define WEAPON_ANIM_LOOP_FRAME                          32
539 #else
540 #define WEAPON_ANIM_LOOP_FRAME                          52                      // frame (from 0) to loop weapon anim
541 #endif
542
543 #define WEAPON_ICON_FRAME_NORMAL                                0
544 #define WEAPON_ICON_FRAME_HOT                                   1
545 #define WEAPON_ICON_FRAME_SELECTED                      2
546 #define WEAPON_ICON_FRAME_DISABLED                      3
547
548 // Weapn loadout specific buttons
549 #define NUM_WEAPON_BUTTONS                                              7
550 #define WL_BUTTON_SCROLL_PRIMARY_UP                     0
551 #define WL_BUTTON_SCROLL_PRIMARY_DOWN           1
552 #define WL_BUTTON_SCROLL_SECONDARY_UP           2
553 #define WL_BUTTON_SCROLL_SECONDARY_DOWN 3
554 #define WL_BUTTON_RESET                                                 4
555 #define WL_BUTTON_DUMMY                                                 5
556 #define WL_BUTTON_MULTI_LOCK                                    6
557 UI_WINDOW       Weapon_ui_window;
558 //UI_BUTTON     Weapon_buttons[NUM_WEAPON_BUTTONS];
559
560 static const char *Wl_mask_single[GR_NUM_RESOLUTIONS] = {
561         "weaponloadout-m",
562         "2_weaponloadout-m"
563 };
564
565 static const char *Wl_mask_multi[GR_NUM_RESOLUTIONS] = {
566         "weaponloadoutmulti-m",
567         "2_weaponloadoutmulti-m"
568 };
569
570 static const char *Wl_loadout_select_mask[GR_NUM_RESOLUTIONS] = {
571         "weaponloadout-m",
572         "2_weaponloadout-m"
573 };
574
575
576 static const char *Weapon_select_background_fname[GR_NUM_RESOLUTIONS] = {
577 #ifdef MAKE_FS1
578         "Brief",
579         "Brief"
580 #else
581         "WeaponLoadout",
582         "2_WeaponLoadout"
583 #endif
584 };
585
586 static const char *Weapon_select_multi_background_fname[GR_NUM_RESOLUTIONS] = {
587 #ifdef MAKE_FS1
588         "Brief",
589         "Brief"
590 #else
591         "WeaponLoadoutMulti",
592         "2_WeaponLoadoutMulti"
593 #endif
594 };
595
596 int Weapon_select_background_bitmap;    // bitmap for weapon select brackground
597
598 static MENU_REGION      Weapon_select_region[NUM_WEAPON_REGIONS];
599 static int                              Num_weapon_select_regions;
600
601 // Mask bitmap pointer and Mask bitmap_id
602 static bitmap*  WeaponSelectMaskPtr;            // bitmap pointer to the weapon select mask bitmap
603 static ubyte*   WeaponSelectMaskData;   // pointer to actual bitmap data
604 static int              Weaponselect_mask_w, Weaponselect_mask_h;
605 static int              WeaponSelectMaskBitmap; // bitmap id of the weapon select mask bitmap
606
607
608 // convenient struct for handling all button controls
609 struct wl_buttons {
610         const char *filename;
611         int x, y, xt, yt;
612         int hotspot;
613         UI_BUTTON button;  // because we have a class inside this struct, we need the constructor below..
614
615         wl_buttons(const char *name, int x1, int y1, int xt1, int yt1, int h) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h) {}
616 };
617
618 static wl_buttons Buttons[GR_NUM_RESOLUTIONS][NUM_WEAPON_BUTTONS] = {
619         {
620 #ifdef MAKE_FS1
621                 wl_buttons("WLB_26",    0,              123,    -1,     -1,     26),
622                 wl_buttons("WLB_27",    0,              272,    -1,     -1,     27),
623                 wl_buttons("WLB_26",    0,              302,    -1,     -1,     8),
624                 wl_buttons("WLB_27",    0,              452,    -1,     -1,     9),
625                 wl_buttons("ssb_39",    566,    317,    -1,     -1,     39),
626                 wl_buttons("ssb_39",    0,              0,              -1,     -1,     99),
627                 wl_buttons("TSB_34",    601,    344,    -1,     -1,     50)
628 #else
629                 wl_buttons("WLB_26",            24,     125,            -1,             -1,     26),
630                 wl_buttons("WLB_27",            24,     276,            -1,             -1,     27),
631                 wl_buttons("WLB_08",            24,     303,            -1,             -1,     8),
632                 wl_buttons("WLB_09",            24,     454,            -1,             -1,     9),
633                 wl_buttons("ssb_39",            571,    347,            -1,             -1,     39),
634                 wl_buttons("ssb_39",            0,              0,                      -1,             -1,     99),
635                 wl_buttons("TSB_34",            603,    374,            -1,             -1,     34)
636 #endif
637         },
638         {
639                 wl_buttons("2_WLB_26",  39,     200,            -1,             -1,     26),
640                 wl_buttons("2_WLB_27",  39,     442,            -1,             -1,     27),
641                 wl_buttons("2_WLB_08",  39,     485,            -1,             -1,     8),
642                 wl_buttons("2_WLB_09",  39,     727,            -1,             -1,     9),
643                 wl_buttons("2_ssb_39",  913,    556,            -1,             -1,     39),
644                 wl_buttons("2_ssb_39",  0,              0,                      -1,             -1,     99),
645                 wl_buttons("2_TSB_34",  966,    599,            -1,             -1,     34)
646         }
647 };
648
649 //static wl_bitmap_group wl_button_bitmaps[NUM_WEAPON_BUTTONS];
650
651 static int Weapon_button_scrollable[NUM_WEAPON_BUTTONS] = {0, 0, 0, 0, 0, 0, 0};
652
653 #define MAX_WEAPON_ICONS_ON_SCREEN 8
654
655 // X and Y locations of the weapon icons in the scrollable lists
656 //int Weapon_icon_x[MAX_WEAPON_ICONS_ON_SCREEN] = {27, 27, 27, 27, 36, 36, 36, 36};
657 //int Weapon_icon_y[MAX_WEAPON_ICONS_ON_SCREEN] = {152, 182, 212, 242, 331, 361, 391, 421};
658 static int Wl_weapon_icon_coords[GR_NUM_RESOLUTIONS][MAX_WEAPON_ICONS_ON_SCREEN][2] = {
659         {
660                 {27, 152},
661                 {27, 182},
662                 {27, 212},
663                 {27, 242},
664                 {36, 331},
665                 {36, 361},
666                 {36, 391},
667                 {36, 421}
668         },
669         {
670                 {59, 251},
671                 {59, 299},
672                 {59, 347},
673                 {59, 395},
674                 {59, 538},
675                 {59, 586},
676                 {59, 634},
677                 {59, 682}
678         }
679 };
680
681
682 static int Wl_bank_coords[GR_NUM_RESOLUTIONS][MAX_WL_WEAPONS][2] = {
683         {
684 #ifdef MAKE_FS1
685                 {106,127},
686                 {106,154},
687                 {106,181},
688                 {324,127},
689                 {324,154},
690                 {324,181},
691                 {324,208},
692 #else
693                 {106,127},
694                 {106,158},
695                 {106,189},
696                 {322,127},
697                 {322,158},
698                 {322,189},
699                 {322,220},
700 #endif
701         },
702         {
703                 {170,203},
704                 {170,246},
705                 {170,290},
706                 {552,203},
707                 {552,246},
708                 {552,290},
709                 {552,333},
710         }
711 };
712
713 static int Wl_bank_count_draw_flags[MAX_WL_WEAPONS] = { 
714         0, 0, 0,                        // primaries -- dont draw counts
715         1, 1, 1, 1              // secondaries -- do draw counts
716 };
717
718
719 static int Weapon_anim_class = -1;
720 static int Last_wl_ship_class;
721
722 static int Wl_overhead_coords[GR_NUM_RESOLUTIONS][2] = {
723         {
724                 // GR_640
725 #ifdef MAKE_FS1
726                 93, 117
727 #else
728                 91, 117
729 #endif
730         },                      
731         {
732                 // GR_1024
733                 156, 183
734         }
735 };
736
737 static int Wl_weapon_ani_coords[GR_NUM_RESOLUTIONS][2] = {
738         {
739 #ifdef MAKE_FS1
740                 384, 116
741 #else
742                 408, 82                 // GR_640
743 #endif
744         },
745         {
746                 648, 128                        // GR_1024
747         }
748 };
749
750 static int Wl_weapon_ani_coords_multi[GR_NUM_RESOLUTIONS][2] = {
751         {
752 #ifdef MAKE_FS1
753                 385, 118
754 #else
755                 408, 143                        // GR_640
756 #endif
757         },
758         {
759                 648, 226                        // GR_1024
760         }
761 };
762
763
764 static int Wl_weapon_desc_coords[GR_NUM_RESOLUTIONS][2] = {
765         {
766                 508, 283                // GR_640
767         },
768         {
769                 813, 453                // GR_1024
770         }
771 };
772
773 static int Wl_delta_x, Wl_delta_y;
774
775 static int Wl_ship_name_coords[GR_NUM_RESOLUTIONS][2] = {
776         {
777                 85, 106
778         },
779         {
780                 136, 170
781         }
782 };
783
784
785 ///////////////////////////////////////////////////////////////////////
786 // UI data structs
787 ///////////////////////////////////////////////////////////////////////
788 typedef struct wl_ship_class_info
789 {
790         int                             overhead_bitmap;
791         anim_t                          *anim;
792         anim_instance_t *anim_instance;
793 } wl_ship_class_info;
794
795 wl_ship_class_info      Wl_ships[MAX_SHIP_TYPES];
796
797 typedef struct wl_icon_info
798 {
799         int                             icon_bmaps[NUM_ICON_FRAMES];
800         int                             current_icon_bmap;
801         int                             can_use;
802         anim_t                          *anim;
803         anim_instance_t *anim_instance;
804 } wl_icon_info;
805
806 wl_icon_info    Wl_icons_teams[MAX_TEAMS][MAX_WEAPON_TYPES];
807 wl_icon_info    *Wl_icons;
808
809 int Plist[MAX_WEAPON_TYPES];    // used to track scrolling of primary icon list
810 int Plist_start, Plist_size;
811
812 int Slist[MAX_WEAPON_TYPES];    // used to track scrolling of primary icon list
813 int Slist_start, Slist_size;
814
815 static int Selected_wl_slot = -1;                       // Currently selected ship slot
816 static int Selected_wl_class = -1;                      // Class of weapon that is selected
817 static int Hot_wl_slot = -1;                                    //      Ship slot that mouse is over (0..11)
818 static int Hot_weapon_icon = -1;                                // Icon number (0-7) which has mouse over it
819 static int Hot_weapon_bank = -1;                                // index (0-7) for weapon slot on ship that has a droppable icon over it
820 static int Hot_weapon_bank_icon = -1;
821
822 static int Wl_mouse_down_on_region = -1;
823
824
825 // weapon desc stuff
826 #ifndef MAKE_FS1
827 #define WEAPON_DESC_WIPE_TIME                   1.5f                    // time in seconds for wipe to occur (over WEAPON_DESC_MAX_LENGTH number of chars)
828 #define WEAPON_DESC_MAX_LINES                   7                               // max lines in the description incl. title
829 #define WEAPON_DESC_MAX_LENGTH          50                              // max chars per line of description text
830 static int Weapon_desc_wipe_done = 0;
831 static float Weapon_desc_wipe_time_elapsed = 0.0f;
832 static char Weapon_desc_lines[WEAPON_DESC_MAX_LINES][WEAPON_DESC_MAX_LENGTH];                   // 1st 2 lines are title, rest are desc
833
834 // maximum width the weapon title can be -- used in the line breaking 
835 int Weapon_title_max_width[GR_NUM_RESOLUTIONS] = { 200, 320 };
836
837 static int Wl_new_weapon_title_coords[GR_NUM_RESOLUTIONS][2] = {
838         {
839                 408, 75         // GR_640
840         },
841         {
842                 648, 118                // GR_1024
843         }
844 };
845
846 static int Wl_new_weapon_title_coords_multi[GR_NUM_RESOLUTIONS][2] = {
847         {
848                 408, 136                // GR_640
849         },
850         {
851                 648, 216                // GR_1024
852         }
853 };
854
855 static int Wl_new_weapon_desc_coords[GR_NUM_RESOLUTIONS][2] = {
856         {
857                 408, 247                // GR_640
858         },
859         {
860                 648, 395                // GR_1024
861         }
862 };
863
864 static int Wl_new_weapon_desc_coords_multi[GR_NUM_RESOLUTIONS][2] = {
865         {
866                 408, 308                // GR_640
867         },
868         {
869                 648, 493                // GR_1024
870         }
871 };
872 #endif
873
874 // ship select text
875 #ifndef MAKE_FS1
876 #define WEAPON_SELECT_NUM_TEXT                  2
877
878 UI_XSTR Weapon_select_text[GR_NUM_RESOLUTIONS][WEAPON_SELECT_NUM_TEXT] = {
879         { // GR_640
880                 { "Reset",                      1337,           580,    337,    UI_XSTR_COLOR_GREEN, -1, &Buttons[0][WL_BUTTON_RESET].button },
881                 { "Lock",                       1270,           602,    364,    UI_XSTR_COLOR_GREEN, -1, &Buttons[0][WL_BUTTON_MULTI_LOCK].button }
882         }, 
883         { // GR_1024
884                 { "Reset",                      1337,           938,    546,    UI_XSTR_COLOR_GREEN, -1, &Buttons[1][WL_BUTTON_RESET].button },
885                 { "Lock",                       1270,           964,    584,    UI_XSTR_COLOR_GREEN, -1, &Buttons[1][WL_BUTTON_MULTI_LOCK].button }
886         }
887 };
888 #endif
889
890
891 ///////////////////////////////////////////////////////////////////////
892 // Carried Icon
893 ///////////////////////////////////////////////////////////////////////
894 typedef struct carried_icon
895 {
896         int weapon_class;               // index Wl_icons[] for carried icon (-1 if carried from bank)
897         int num;                                        // number of units of weapon
898         int from_bank;                  // bank index that icon came from (0..2 primary, 3..6 secondary).  -1 if from list
899         int from_slot;                  // ship slot that weapon is part of 
900         int from_x, from_y;
901 } carried_icon;
902
903 static carried_icon Carried_wl_icon;
904
905 // forward declarations
906 void draw_wl_icons();
907 void wl_draw_ship_weapons(int index);
908 void wl_pick_icon_from_list(int index);
909 void pick_from_ship_slot(int num);
910 void start_weapon_animation(int weapon_class);
911 void stop_weapon_animation();
912 void wl_start_slot_animation(int n);
913 int wl_get_pilot_subsys_index(p_object *pobjp);
914
915 void wl_reset_to_defaults();
916
917 void wl_set_selected_slot(int slot_num);
918 void wl_maybe_reset_selected_slot();
919 void wl_maybe_reset_selected_weapon_class();
920
921 void wl_render_icon_count(int num, int x, int y);
922 void wl_render_weapon_desc();
923
924
925
926 // carry icon functions
927 void wl_reset_carried_icon();
928 int wl_icon_being_carried();
929 void wl_set_carried_icon(int from_bank, int from_slot, int weapon_class);
930
931
932 // Determine hack offset for how to draw fury missile icon. 
933 int wl_fury_missile_offset_hack(int weapon_class, int num_missiles)
934 {
935         if ( weapon_class < 0 ) {
936                 return 0;
937         }
938
939         if ( num_missiles < 100 ) {
940                 return 0 ;
941         }                       
942
943         if ( !SDL_strncasecmp(Weapon_info[weapon_class].name, NOX("fury"), 4) ) {
944                 return 3;
945         }
946
947         return 0;
948 }
949
950 const char *wl_tooltip_handler(const char *str)
951 {
952         if (Selected_wl_class < 0)
953                 return NULL;
954
955         if (!SDL_strcasecmp(str, "@weapon_desc")) {
956                 char *desc;
957                 int x, y, w, h;
958
959                 desc = Weapon_info[Selected_wl_class].desc;
960                 gr_get_string_size(&w, &h, desc);
961                 x = Wl_weapon_desc_coords[gr_screen.res][0] - w / 2;
962                 y = Wl_weapon_desc_coords[gr_screen.res][1] - h / 2;
963
964                 gr_set_color_fast(&Color_black);
965                 gr_rect(x - 5, y - 5, w + 10, h + 10);
966
967                 gr_set_color_fast(&Color_bright_white);
968                 gr_string(x, y, desc);
969                 return NULL;
970         }
971
972         return NULL;
973 }
974
975 // reset the data inside the Carried_wl_icon
976 void wl_reset_carried_icon()
977 {
978         Carried_wl_icon.weapon_class = -1;
979         Carried_wl_icon.num = 0;
980         Carried_wl_icon.from_bank = -1;
981         Carried_wl_icon.from_slot = -1;
982 }
983
984 // Is an icon being carried?
985 int wl_icon_being_carried()
986 {
987         if ( Carried_wl_icon.weapon_class >= 0 ) {
988                 return 1;
989         }
990
991         return 0;
992 }
993
994 // Set carried icon data 
995 void wl_set_carried_icon(int from_bank, int from_slot, int weapon_class)
996 {
997         int mx,my;
998
999         Carried_wl_icon.from_bank = from_bank;
1000         Carried_wl_icon.from_slot = from_slot;
1001         Carried_wl_icon.weapon_class = weapon_class;
1002
1003         mouse_get_pos( &mx, &my );
1004         Carried_wl_icon.from_x=mx;
1005         Carried_wl_icon.from_y=my;
1006
1007         Buttons[gr_screen.res][WL_BUTTON_DUMMY].button.capture_mouse();
1008 }
1009
1010 // determine if the carried icon has moved
1011 int wl_carried_icon_moved()
1012 {
1013         int mx, my;
1014         mouse_get_pos( &mx, &my );
1015         if ( Carried_wl_icon.from_x != mx || Carried_wl_icon.from_y != my) {
1016                 return 1;
1017         }
1018
1019         return 0;
1020 }
1021
1022 // return the index for the pilot subsystem in the parse object
1023 int wl_get_pilot_subsys_index(p_object *pobjp)
1024 {
1025         int pilot_index, start_index, end_index, i;
1026
1027         // see if there is a PILOT subystem
1028         start_index = pobjp->subsys_index;
1029         end_index = start_index + pobjp->subsys_count;
1030         pilot_index = -1;
1031         for ( i = start_index; i < end_index; i++ ) {
1032                 if ( !SDL_strcasecmp(Subsys_status[i].name, NOX("pilot") ) ) {
1033                         pilot_index = i;
1034                         break;
1035                 }
1036         }
1037
1038         if ( pilot_index == -1 ) {
1039                 Error(LOCATION,"Parse object doesn't have a pilot subsystem\n");
1040                 return -1;
1041         }
1042
1043         return pilot_index;
1044 }
1045
1046 // Pause the current weapon animation
1047 void wl_pause_anim()
1048 {
1049         if ( Weapon_anim_class >= 0 && Wl_icons[Weapon_anim_class].anim_instance ) {
1050                 anim_pause(Wl_icons[Weapon_anim_class].anim_instance);
1051         }
1052 }
1053
1054 // Unpause the current weapon animation
1055 void wl_unpause_anim()
1056 {
1057         if ( Weapon_anim_class >= 0 && Wl_icons[Weapon_anim_class].anim_instance ) {
1058                 anim_unpause(Wl_icons[Weapon_anim_class].anim_instance);
1059         }
1060 }
1061
1062 // ---------------------------------------------------------------------------------
1063 // weapon_button_do()
1064 //
1065 void weapon_button_do(int i)
1066 {
1067         switch ( i ) {
1068                         case PRIMARY_SCROLL_UP:
1069                                 if ( common_scroll_up_pressed(&Plist_start, Plist_size, 4) ) {
1070                                         gamesnd_play_iface(SND_SCROLL);
1071                                 } else {
1072                                         gamesnd_play_iface(SND_GENERAL_FAIL);
1073                                 }
1074                         break;
1075
1076                         case PRIMARY_SCROLL_DOWN:
1077                                 if ( common_scroll_down_pressed(&Plist_start, Plist_size, 4) ) {
1078                                         gamesnd_play_iface(SND_SCROLL);
1079                                 } else {
1080                                         gamesnd_play_iface(SND_GENERAL_FAIL);
1081                                 }
1082                         break;
1083
1084                         case SECONDARY_SCROLL_UP:
1085                                 if ( common_scroll_up_pressed(&Slist_start, Slist_size, 4) ) {
1086                                         gamesnd_play_iface(SND_SCROLL);
1087                                 } else {
1088                                         gamesnd_play_iface(SND_GENERAL_FAIL);
1089                                 }
1090                         break;
1091
1092                         case SECONDARY_SCROLL_DOWN:
1093                                 if ( common_scroll_down_pressed(&Slist_start, Slist_size, 4) ) {
1094                                         gamesnd_play_iface(SND_SCROLL);
1095                                 } else {
1096                                         gamesnd_play_iface(SND_GENERAL_FAIL);
1097                                 }
1098                         break;
1099
1100                         case WL_RESET_BUTTON_MASK:
1101                                 wl_reset_to_defaults();
1102                                 break;
1103
1104                         case WL_BUTTON_MULTI_LOCK:
1105                                 SDL_assert(Game_mode & GM_MULTIPLAYER);                         
1106                                 // the "lock" button has been pressed
1107                                 multi_ts_lock_pressed();
1108
1109                                 // disable the button if it is now locked
1110                                 if(multi_ts_is_locked()){
1111                                         Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.disable();
1112                                 }
1113                                 break;
1114
1115                         default:
1116                         break;
1117         }
1118 }
1119
1120 // -------------------------------------------------------------------
1121 // weapon_check_buttons()
1122 //
1123 // Check if any weapons loadout screen buttons have been pressed, and 
1124 // call weapon_button_do() if they have.
1125 //
1126 void weapon_check_buttons()
1127 {
1128         int                     i;
1129         wl_buttons      *b;
1130
1131         for ( i = 0; i < NUM_WEAPON_BUTTONS; i++ ) {
1132                 b = &Buttons[gr_screen.res][i];
1133                 
1134                 if ( b->button.pressed() ) {
1135                         if(i == WL_BUTTON_MULTI_LOCK){
1136                                 weapon_button_do(i);
1137                         } else {
1138                                 weapon_button_do(b->hotspot);
1139                         }
1140                 }
1141         }
1142 }
1143
1144 // -------------------------------------------------------------------
1145 // wl_redraw_pressed_buttons()
1146 //
1147 // Redraw any weapon loadout buttons that are pressed down.  This function is needed
1148 // since we sometimes need to draw pressed buttons last to ensure the entire
1149 // button gets drawn (and not overlapped by other buttons)
1150 //
1151 void wl_redraw_pressed_buttons()
1152 {
1153         int                     i;
1154         wl_buttons      *b;
1155         
1156         common_redraw_pressed_buttons();
1157
1158         for ( i = 0; i < NUM_WEAPON_BUTTONS; i++ ) {
1159                 b = &Buttons[gr_screen.res][i];
1160                 if ( b->button.button_down() ) {
1161                         b->button.draw_forced(2);
1162                 }
1163         }
1164 }
1165
1166 // ---------------------------------------------------------------------------------
1167 // weapon_buttons_init()
1168 //
1169 void weapon_buttons_init()
1170 {
1171         wl_buttons      *b;
1172         int                     i;
1173
1174         for ( i = 0; i < NUM_WEAPON_BUTTONS; i++ ) {
1175                 b = &Buttons[gr_screen.res][i];
1176                 b->button.create( &Weapon_ui_window, "", Buttons[gr_screen.res][i].x, Buttons[gr_screen.res][i].y, 60, 30, Weapon_button_scrollable[i]);
1177                 // set up callback for when a mouse first goes over a button
1178                 b->button.set_highlight_action( common_play_highlight_sound );
1179                 b->button.set_bmaps(Buttons[gr_screen.res][i].filename);
1180                 b->button.link_hotspot(Buttons[gr_screen.res][i].hotspot);
1181         }
1182
1183         if ( Game_mode & GM_MULTIPLAYER ) {
1184                 Buttons[gr_screen.res][WL_BUTTON_RESET].button.hide();
1185                 Buttons[gr_screen.res][WL_BUTTON_RESET].button.disable();               
1186
1187                 // if we're not the host of the game (or a team captain in team vs. team mode), disable the lock button
1188                 if(Netgame.type_flags & NG_TYPE_TEAM){
1189                         if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1190                                 Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.disable();          
1191                         }
1192                 } else {
1193                         if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1194                                 Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.disable();                          
1195                         }
1196                 }
1197         } else {                
1198                 Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.hide();
1199                 Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.disable();
1200         }
1201
1202 #ifndef MAKE_FS1
1203         // add all xstrs
1204         for(i=0; i<WEAPON_SELECT_NUM_TEXT; i++) {
1205                 Weapon_ui_window.add_XSTR(&Weapon_select_text[gr_screen.res][i]);
1206         }
1207 #endif
1208
1209         Buttons[gr_screen.res][WL_BUTTON_DUMMY].button.hide();
1210         Buttons[gr_screen.res][WL_BUTTON_DUMMY].button.disable();       
1211 }
1212
1213 // ---------------------------------------------------------------------------------
1214 // wl_render_overhead_view()
1215 //
1216 void wl_render_overhead_view(float frametime)
1217 {
1218         char                                            name[NAME_LENGTH + CALLSIGN_LEN];
1219         wl_ship_class_info      *wl_ship;
1220         int                                             ship_class;
1221
1222         if ( Selected_wl_slot == -1 ) {
1223                 return;
1224         }
1225
1226         ship_class = Wss_slots[Selected_wl_slot].ship_class;
1227
1228         // check if ship class has changed and maybe play sound
1229         if (Last_wl_ship_class != ship_class) {
1230                 if (Last_wl_ship_class != -1) {
1231                         gamesnd_play_iface(SND_ICON_DROP);
1232                 }
1233                 Last_wl_ship_class = ship_class;
1234         }
1235
1236         wl_ship = &Wl_ships[ship_class];
1237
1238         if ( wl_ship->anim_instance == NULL ) {
1239                 if ( wl_ship->overhead_bitmap < 0 ) {
1240                         // load the bitmap
1241                         if (gr_screen.res == GR_640)
1242                         {
1243                                 // lo-res
1244                                 wl_ship->overhead_bitmap = bm_load(Ship_info[ship_class].overhead_filename);
1245                         } else {
1246                                 // high-res
1247                                 char filename[NAME_LENGTH+2] = "2_";
1248                                 SDL_strlcat(filename, Ship_info[ship_class].overhead_filename, SDL_arraysize(filename));
1249                                 wl_ship->overhead_bitmap = bm_load(filename);
1250                         }
1251                         if ( wl_ship->overhead_bitmap < 0 ) {
1252                                 Int3();                 // bad things happened
1253                                 return;
1254                         }
1255                 }
1256                 gr_set_bitmap(wl_ship->overhead_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1257                 gr_bitmap(Wl_overhead_coords[gr_screen.res][0], Wl_overhead_coords[gr_screen.res][1]);
1258         }
1259
1260         ss_return_name(Selected_wl_slot/4, Selected_wl_slot%4, name, SDL_arraysize(name));
1261         gr_set_color_fast(&Color_normal);
1262         gr_string(Wl_ship_name_coords[gr_screen.res][0], Wl_ship_name_coords[gr_screen.res][1], name);
1263 }
1264
1265 // ---------------------------------------------------------------------------------
1266 // wl_get_ship_class()
1267 //
1268 //
1269 int wl_get_ship_class(int wl_slot)
1270 {
1271         return Wss_slots[wl_slot].ship_class;
1272 }
1273
1274 //      Return true if weapon_flags indicates a weapon that is legal for use in current game type.
1275 //      Function added by MK on 9/6/99 to support separate legal loadouts for dogfight missions.
1276 int weapon_allowed_for_game_type(int weapon_flags)
1277 {
1278         int     rval = 0;
1279
1280 /* disable check for demo since it doesn't have "$Allowed Dogfight PBanks" */
1281 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
1282         if ((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)) {
1283                 if (weapon_flags & (1 << 1))
1284                         rval = 1;
1285         } else
1286 #endif  
1287         if (weapon_flags & (1 << 0))
1288                 rval  = 1;
1289
1290         return rval;
1291 }
1292
1293 // go through the possible weapons to choose from, and flag some as disabled since
1294 // that ship class cannot use that kind of weapon.  The weapon filter is specified
1295 // in ships.tbl, where each ship has a list of all the possible weapons it can use.
1296 void wl_set_disabled_weapons(int ship_class)
1297 {
1298         int                             i;
1299         ship_info               *sip;
1300
1301         if ( ship_class == - 1 )
1302                 return;
1303
1304         SDL_assert(ship_class >= 0 && ship_class < MAX_SHIP_TYPES);
1305
1306         sip = &Ship_info[ship_class];
1307
1308         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1309                 //      Determine whether weapon #i is allowed on this ship class in the current type of mission.
1310                 //      As of 9/6/99, the only difference is dogfight missions have a different list of legal weapons.
1311                 Wl_icons[i].can_use = weapon_allowed_for_game_type(sip->allowed_weapons[i]);
1312         }
1313 }
1314
1315 // ---------------------------------------------------------------------------------
1316 // maybe_select_wl_slot()
1317 //
1318 // A slot index was clicked on, mabye change Selected_wl_slot
1319 void maybe_select_wl_slot(int block, int slot)
1320 {
1321         int sidx;
1322
1323         if ( Wss_num_wings <= 0 )
1324                 return;
1325
1326         sidx = block*4 + slot;
1327         if ( Wss_slots[sidx].ship_class < 0 ) {
1328                 return;
1329         }
1330
1331         wl_set_selected_slot(sidx);
1332 }
1333
1334 // ---------------------------------------------------------------------------------
1335 // maybe_select_new_weapon()
1336 //
1337 // Change to the weapon that corresponds to index in the weapon list
1338 //
1339 // input:       index           =>              weapon icon index (0-7)
1340 //
1341 void maybe_select_new_weapon(int index)
1342 {
1343         int weapon_class;
1344
1345         // if a weapon is being carried, do nothing
1346         if ( wl_icon_being_carried() ) {
1347                 return;
1348         }
1349
1350         int region_index = ICON_PRIMARY_0+index;
1351         if ( index > 3 ) {
1352                 region_index = ICON_SECONDARY_0 + (index - 4);
1353         }
1354
1355         if ( Wl_mouse_down_on_region != region_index ) {
1356                 return;
1357         }
1358
1359         if ( index < 4 ) {
1360                 weapon_class = Plist[Plist_start+index];
1361         } else {
1362                 weapon_class = Slist[Slist_start+index-4];
1363         }
1364
1365         if ( weapon_class >= 0 ) {
1366                 Selected_wl_class = weapon_class;
1367                 wl_pick_icon_from_list(index);
1368         }
1369 }
1370
1371 // ---------------------------------------------------------------------------------
1372 // maybe_select_new_ship_weapon()
1373 //
1374 // Change to the weapon that corresponds to the ship weapon slot
1375 //
1376 // input: index ->      index of bank (0..2 primary, 0..6 secondary)
1377 void maybe_select_new_ship_weapon(int index)
1378 {
1379         int *wep, *wep_count;
1380
1381         if ( Selected_wl_slot == -1 )
1382                 return;
1383
1384         if ( wl_icon_being_carried() ) {
1385                 return;
1386         }
1387
1388         wep = Wss_slots[Selected_wl_slot].wep;
1389         wep_count = Wss_slots[Selected_wl_slot].wep_count;
1390
1391         if ( wep[index] < 0 || wep_count[index] <= 0 ) {
1392                 return;
1393         }
1394
1395         if ( Wl_mouse_down_on_region != (ICON_SHIP_PRIMARY_0+index) ) {
1396                 return;
1397         }
1398
1399
1400         Selected_wl_class = wep[index];
1401 }
1402
1403 // Initialize Wl_pool[] to mission deafult
1404 void wl_init_pool(team_data *td)
1405 {
1406         int i;
1407
1408         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1409                 Wl_pool[i] = -1;
1410         }
1411
1412         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1413                 Wl_pool[i] = td->weaponry_pool[i];      // read from mission
1414         }
1415 }
1416
1417 // load the icons for a specific ship class
1418 void wl_load_icons(int weapon_class)
1419 {
1420         wl_icon_info    *icon;
1421         int                             first_frame, num_frames, i;
1422
1423         icon = &Wl_icons[weapon_class];
1424
1425         first_frame = bm_load_animation(Weapon_info[weapon_class].icon_filename, &num_frames);
1426         if ( first_frame == -1 ) {
1427                 Int3(); // Could not load in icon frames.. get Alan
1428                 return;
1429         }
1430
1431         for ( i = 0; i < num_frames ; i++ ) {
1432                 icon->icon_bmaps[i] = first_frame+i;
1433         }
1434 }
1435
1436 // Load in a specific weapon animation.  The data is loaded as a memory-mapped file since these animations
1437 // can be large.
1438 void wl_load_anim(int weapon_class)
1439 {
1440         char animation_filename[CF_MAX_FILENAME_LENGTH+4];
1441         wl_icon_info    *icon;
1442
1443         icon = &Wl_icons[weapon_class];
1444         SDL_assert( icon->anim == NULL );
1445         
1446         // 1024x768 SUPPORT
1447         // If we are in 1024x768, we first want to append "2_" in front of the filename
1448         if (gr_screen.res == GR_1024) {
1449                 SDL_assert(strlen(Weapon_info[weapon_class].anim_filename) <= 30);
1450                 SDL_strlcpy(animation_filename, "2_", SDL_arraysize(animation_filename));
1451                 SDL_strlcat(animation_filename, Weapon_info[weapon_class].anim_filename, SDL_arraysize(animation_filename));
1452
1453                 // now check if file exists
1454                 // GRR must add a .ANI at the end for detection
1455                 SDL_strlcat(animation_filename,".ani", SDL_arraysize(animation_filename));
1456                 icon->anim = anim_load(animation_filename);
1457
1458                 if (icon->anim == NULL) {
1459                         mprintf(("Weapon ANI: Can not find %s, using lowres version instead.\n",animation_filename)); 
1460                         SDL_strlcpy(animation_filename, Weapon_info[weapon_class].anim_filename, SDL_arraysize(animation_filename));
1461                         icon->anim = anim_load(animation_filename);
1462                 }
1463
1464                 /*
1465                 if (!cf_exist(animation_filename, CF_TYPE_INTERFACE)) {
1466                         // file does not exist, use original low res version
1467                         mprintf(("Weapon ANI: Can not find %s, using lowres version instead.\n",animation_filename)); 
1468                         strcpy(animation_filename, Weapon_info[weapon_class].anim_filename);
1469                 } else {
1470                         animation_filename[strlen(animation_filename) - 4] = '\0';
1471                         mprintf(("Weapon ANI: Found hires version of %s\n",animation_filename));
1472                 }
1473                 */
1474         } else {
1475                 SDL_strlcpy(animation_filename, Weapon_info[weapon_class].anim_filename, SDL_arraysize(animation_filename));
1476                 // load the compressed ship animation into memory 
1477                 icon->anim = anim_load(animation_filename);
1478         }
1479
1480         if ( icon->anim == NULL ) {
1481                 Int3();         // couldn't load anim filename.. get Alan
1482         }
1483 }
1484
1485 // Load in any weapon animations.  This function assumes that Wl_pool has been inited.
1486 void wl_load_all_anims()
1487 {
1488         #ifndef DEMO // not for FS2_DEMO
1489
1490         int i;
1491
1492         // init anim members for weapon animations
1493         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1494                 Wl_icons[i].anim = NULL;
1495                 Wl_icons[i].anim_instance = NULL;
1496         }
1497
1498         // init anim member for overhead ship animations
1499         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1500                 Wl_ships[i].anim = NULL;
1501                 Wl_ships[i].anim_instance = NULL;
1502         }
1503
1504         // load up the animations used for weapons (they are memory-mapped)
1505         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1506                 if ( Wl_pool[i] > 0 ) {
1507                         wl_load_anim(i);
1508                 }
1509         }
1510
1511         #endif
1512 }
1513
1514 // release any anim instances
1515 void wl_unload_all_anim_instances()
1516 {
1517         // stop any weapon anim instances
1518         for ( int i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1519                 if ( Wl_icons[i].anim_instance ) {
1520                         anim_release_render_instance(Wl_icons[i].anim_instance);
1521                         Wl_icons[i].anim_instance = NULL;
1522                 }
1523         }
1524
1525         // stop any overhead anim instances
1526         for (int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1527                 if ( Wl_ships[i].anim_instance ) {
1528                         anim_release_render_instance(Wl_ships[i].anim_instance);
1529                         Wl_ships[i].anim_instance = NULL;
1530                 }
1531         }
1532 }
1533
1534 // free source anim data if allocated
1535 void wl_unload_all_anims()
1536 {
1537         int i;
1538
1539         // unload overhead anim instances
1540         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1541                 if ( Wl_ships[i].anim ) {
1542                         anim_free(Wl_ships[i].anim);
1543                         Wl_ships[i].anim = NULL;
1544                 }
1545         }
1546
1547         // unload weapon anim instances
1548         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1549                 if ( Wl_icons[i].anim ) {
1550                         anim_free(Wl_icons[i].anim);
1551                         Wl_icons[i].anim = NULL;
1552                 }
1553         }
1554 }
1555
1556 // load all the icons for weapons in the pool
1557 void wl_load_all_icons()
1558 {
1559         #ifndef DEMO // not for FS2_DEMO
1560
1561         int i, j;
1562
1563         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1564                 // clear out data
1565                 Wl_icons[i].anim = NULL;
1566                 Wl_icons[i].anim_instance = NULL;
1567                 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
1568                         Wl_icons[i].icon_bmaps[j] = -1;
1569                 }
1570
1571                 if ( Wl_pool[i] > 0 ) {
1572                         wl_load_icons(i);
1573                 }
1574         }
1575
1576         #endif
1577 }
1578
1579 //      wl_unload_icons() frees the bitmaps used for weapon icons 
1580 void wl_unload_icons()
1581 {
1582         int                                     i,j;
1583         wl_icon_info            *icon;
1584
1585         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1586                 icon = &Wl_icons[i];
1587
1588                 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
1589                         if ( icon->icon_bmaps[j] >= 0 ) {
1590                                 bm_release(icon->icon_bmaps[j]);
1591                                 icon->icon_bmaps[j] = -1;
1592                         }
1593                 }
1594         }
1595 }
1596
1597 // init ship-class specific data
1598 void wl_init_ship_class_data()
1599 {
1600         int i;
1601         wl_ship_class_info      *wl_ship;
1602
1603         for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
1604                 wl_ship = &Wl_ships[i];
1605                 wl_ship->overhead_bitmap = -1;
1606                 wl_ship->anim = NULL;
1607                 wl_ship->anim_instance = NULL;
1608         }
1609 }
1610
1611 // free any allocated ship-class specific data
1612 void wl_free_ship_class_data()
1613 {
1614         int i;
1615         wl_ship_class_info      *wl_ship;
1616
1617         for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
1618                 wl_ship = &Wl_ships[i];
1619
1620                 if ( wl_ship->overhead_bitmap != -1 ) {
1621                         bm_release(wl_ship->overhead_bitmap);
1622                         wl_ship->overhead_bitmap = -1;
1623                 }
1624
1625                 if ( wl_ship->anim != NULL ) {
1626                         wl_ship->anim = NULL;
1627                 }
1628
1629                 if ( wl_ship->anim_instance != NULL ) {
1630                         wl_ship->anim_instance = NULL;
1631                 }
1632         }
1633 }
1634
1635 // Set selected slot to first placed ship
1636 void wl_reset_selected_slot()
1637 {
1638         int i;
1639         Selected_wl_slot = -1;
1640
1641         // in multiplayer, select the slot of the player's ship by default
1642         if((Game_mode & GM_MULTIPLAYER) && !MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM]) && (Wss_slots[Net_player->p_info.ship_index].ship_class >= 0)){
1643                 wl_set_selected_slot(Net_player->p_info.ship_index);
1644                 return;
1645         }
1646
1647         for ( i=0; i<MAX_WSS_SLOTS; i++ ) {
1648                 if ( !ss_disabled_slot(i) ) {
1649                         if ( ss_wing_slot_is_console_player(i) && (Wss_slots[i].ship_class >= 0) ) {
1650                                 wl_set_selected_slot(i);
1651                                 return;
1652                         }
1653                 }
1654         }
1655
1656         // Didn't locate player ship, so just select the first ship we find
1657         for ( i=0; i<MAX_WSS_SLOTS; i++ ) {
1658                 if ( Wss_slots[i].ship_class >=  0 ) {
1659                         wl_set_selected_slot(i);
1660                         break;
1661                 }
1662         }
1663 }
1664
1665 // called whenever it is possible that the current selected slot has had it's ship disappear
1666 void wl_maybe_reset_selected_slot()
1667 {
1668         int reset=0;
1669
1670         if ( Selected_wl_slot == -1 ) {
1671                 reset = 1;
1672         }
1673
1674         if ( Wss_slots[Selected_wl_slot].ship_class < 0 ) {
1675                 reset = 1;
1676         }
1677
1678         if ( reset ) {
1679                 wl_reset_selected_slot();
1680         }
1681 }
1682
1683 // If Selected_wl_class is -1, choose the first weapon available from the pool for an animation
1684 //  - on second thought, choose the first weapon that is oin the ship, then go to the pools
1685 void wl_maybe_reset_selected_weapon_class()
1686 {
1687         int i;
1688
1689         if ( Selected_wl_class >= 0 ) 
1690                 return;
1691
1692         // try to locate a weapon class to show animation for
1693         // first check for a weapon on the ship
1694         for (i=0; i<MAX_WL_WEAPONS; i++) {
1695                 // if alpha 1 has a weapon in bank i, set it as the selected type
1696                 if (Wss_slots[0].wep_count[i] >= 0) {
1697                         Selected_wl_class = Wss_slots[0].wep[i];
1698                         return;
1699                 }
1700         }
1701
1702         // then check for a primary weapon in the pool
1703         for ( i = 0; i < Plist_size; i++ ) {
1704                 if ( Plist[i] >= 0 ) {
1705                         Selected_wl_class = Plist[i];
1706                         return;
1707                 }
1708         }
1709
1710         // finally, if no others found yet, check for a secondary weapon in the pool
1711         for ( i = 0; i < Slist_size; i++ ) {
1712                 if ( Slist[i] >= 0 ) {
1713                         Selected_wl_class = Slist[i];
1714                         return;
1715                 }
1716         }
1717 }
1718
1719 // start an overhead animation, since selected slot has changed
1720 void wl_start_slot_animation(int n)
1721 {
1722 #ifndef DEMO // not for FS2_DEMO
1723
1724         // don't use ani's
1725         // fallback code in wl_render_overhead_view() will 
1726         // use the .pcx files
1727         // should prolly scrub out the 1e06 lines of dead code this leaves
1728 #ifndef MAKE_FS1
1729         return;
1730 #else
1731         int                                             ship_class;
1732         wl_ship_class_info      *wl_ship;
1733         anim_play_struct                aps;
1734
1735         if ( n < 0 ) {
1736                 return;
1737         }
1738
1739         ship_class = Wss_slots[n].ship_class;
1740         
1741         if ( ship_class < 0 ) {
1742                 Int3();
1743                 return;
1744         }
1745
1746         wl_ship = &Wl_ships[ship_class];
1747
1748         // maybe this animation is already playing?
1749         if ( wl_ship->anim_instance ) {
1750                 anim_stop_playing(wl_ship->anim_instance);
1751                 wl_ship->anim_instance = NULL;
1752         }
1753         
1754         // maybe we have to load this animation
1755         if ( wl_ship->anim == NULL ) {
1756                 wl_ship->anim = anim_load(Ship_info[ship_class].overhead_filename);
1757                 if ( wl_ship->anim == NULL ) {
1758                         Int3();         // couldn't load anim filename.. get Alan
1759                         return;
1760                 }
1761         }
1762
1763         anim_play_init(&aps, wl_ship->anim, Wl_overhead_coords[gr_screen.res][0], Wl_overhead_coords[gr_screen.res][1]);
1764         aps.screen_id = ON_WEAPON_SELECT;
1765         aps.framerate_independent = 1;
1766         aps.skip_frames = 0;
1767         wl_ship->anim_instance = anim_play(&aps);
1768 #endif // !MAKE_FS1
1769 #endif // !DEMO
1770 }
1771
1772 // Call when Selected_wl_slot needs to be changed
1773 void wl_set_selected_slot(int slot_num)
1774 {
1775         if ( (slot_num >= 0) && (slot_num != Selected_wl_slot) ) {
1776                 // slot has changed.... start an animation
1777                 wl_start_slot_animation(slot_num);
1778 /*
1779                 if ( Current_screen == ON_WEAPON_SELECT ) {
1780                         gamesnd_play_iface(SND_OVERHEAD_SHIP_ANIM);
1781                 }
1782 */
1783   }
1784
1785         Selected_wl_slot = slot_num;
1786         if ( Selected_wl_slot >= 0 ) {
1787                 wl_set_disabled_weapons(Wss_slots[slot_num].ship_class);
1788         }
1789 }
1790
1791 // determine how many missiles of type 'wi_index' will fit into capacity
1792 int wl_calc_missile_fit(int wi_index, int capacity)
1793 {
1794         if ( wi_index < 0 ) {
1795                 return 0;
1796         }
1797
1798         SDL_assert(Weapon_info[wi_index].subtype == WP_MISSILE);
1799         return fl2i( capacity / Weapon_info[wi_index].cargo_size + 0.5f );
1800 }
1801
1802 // fill out the weapons for this ship_class
1803 void wl_get_ship_class_weapons(int ship_class, int *wep, int *wep_count)
1804 {
1805         ship_info       *sip;
1806         int i;
1807
1808         SDL_assert(ship_class >= 0 && ship_class < MAX_SHIP_TYPES);
1809         sip = &Ship_info[ship_class];
1810
1811         // reset weapons arrays
1812         for ( i=0; i < MAX_WL_WEAPONS; i++ ) {
1813                 wep[i] = -1;
1814                 wep_count[i] = -1;      // -1 means weapon bank doesn't exist.. 0 just means it is empty
1815         }
1816
1817         for ( i = 0; i < sip->num_primary_banks; i++ ) {
1818                 wep[i] = sip->primary_bank_weapons[i];
1819                 wep_count[i] = 1;
1820         }
1821
1822         for ( i = 0; i < sip->num_secondary_banks; i++ ) {
1823                 wep[i+MAX_WL_PRIMARY] = sip->secondary_bank_weapons[i];
1824                 wep_count[i+MAX_WL_PRIMARY] = wl_calc_missile_fit(sip->secondary_bank_weapons[i], sip->secondary_bank_ammo_capacity[i]);
1825         }
1826 }
1827
1828 // fill out the wep[] and wep_count[] arrays for a ship
1829 void wl_get_ship_weapons(int ship_index, int *wep, int *wep_count)
1830 {
1831         int                     i;
1832         ship_weapon     *swp;
1833
1834         SDL_assert(ship_index >= 0);
1835
1836         swp = &Ships[ship_index].weapons;
1837
1838         for ( i = 0; i < swp->num_primary_banks; i++ ) {
1839                 wep[i] = swp->primary_bank_weapons[i];
1840                 wep_count[i] = 1;
1841                 if ( wep[i] == -1 ) {
1842                         wep_count[i] = 0;
1843                 }
1844         }
1845
1846         for ( i = 0; i < swp->num_secondary_banks; i++ ) {
1847                 wep[i+MAX_WL_PRIMARY] = swp->secondary_bank_weapons[i];
1848                 wep_count[i+MAX_WL_PRIMARY] = swp->secondary_bank_ammo[i];
1849                 if ( wep[i+MAX_WL_PRIMARY] == -1 ) {
1850                         wep_count[i+MAX_WL_PRIMARY] = 0;
1851                 }
1852         }
1853 }
1854
1855 // set wep and wep_count from a ship which sits in the ship_arrivals[] list at index sa_index
1856 void wl_get_parseobj_weapons(int sa_index, int ship_class, int *wep, int *wep_count)
1857 {
1858         int                             i,      pilot_index;
1859         subsys_status   *ss;
1860         ship_info               *sip;
1861         p_object                        *pobjp;
1862
1863         pobjp = &ship_arrivals[sa_index];
1864         sip = &Ship_info[ship_class];
1865
1866         pilot_index = wl_get_pilot_subsys_index(pobjp);
1867
1868         if ( pilot_index == -1 )
1869                 return;
1870
1871         ss = &Subsys_status[pilot_index];
1872
1873         if ( ss->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE ) {
1874                 for ( i=0; i < MAX_PRIMARY_BANKS; i++ ) {
1875                         wep[i] = ss->primary_banks[i];          
1876                 } // end for
1877         }
1878
1879         if ( ss->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE ) {
1880                 for ( i=0; i < MAX_SECONDARY_BANKS; i++ ) {
1881                         wep[i+MAX_WL_PRIMARY] = ss->secondary_banks[i]; 
1882                 } // end for
1883         }
1884
1885         // ammo counts could still be modified
1886         for ( i=0; i < MAX_SECONDARY_BANKS; i++ ) {
1887                 if ( wep[i+MAX_WL_PRIMARY] >= 0 ) {
1888                         wep_count[i+MAX_WL_PRIMARY] = wl_calc_missile_fit(wep[i+MAX_WL_PRIMARY], fl2i(ss->secondary_ammo[i]/100.0f * sip->secondary_bank_ammo_capacity[i] + 0.5f));
1889                 }
1890         }
1891 }
1892
1893 // ensure that there aren't any bogus weapons assigned by default
1894 void wl_cull_illegal_weapons(int ship_class, int *wep, int *wep_count)
1895 {
1896         int i;
1897         for ( i=0; i < MAX_WL_WEAPONS; i++ ) {
1898                 if ( wep[i] < 0 ) {
1899                         continue;
1900                 }
1901
1902                 if ( !weapon_allowed_for_game_type(Ship_info[ship_class].allowed_weapons[wep[i]]) ) {
1903 //                      wep[i] = -1;
1904                         wep_count[i] = 0;
1905                 }
1906         }
1907 }
1908
1909 // get the weapons info that should be on ship by default
1910 void wl_get_default_weapons(int ship_class, int slot_num, int *wep, int *wep_count)
1911 {
1912         int original_ship_class, i;
1913
1914         SDL_assert(slot_num >= 0 && slot_num < MAX_WSS_SLOTS);
1915
1916         // clear out wep and wep_count
1917         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
1918                 wep[i] = -1;
1919                 wep_count[i] = -1;
1920         }
1921
1922         if ( ship_class < 0 )
1923                 return;
1924
1925         original_ship_class = ss_return_original_ship_class(slot_num);
1926
1927         if ( original_ship_class != ship_class ) {
1928                 wl_get_ship_class_weapons(ship_class, wep, wep_count);
1929         } else {
1930                 int sa_index;   // ship arrival index
1931                 sa_index = ss_return_saindex(slot_num);
1932
1933                 if ( sa_index >= 0 ) {
1934                         // still a parse object
1935                         wl_get_ship_class_weapons(ship_class, wep, wep_count);
1936                         wl_get_parseobj_weapons(sa_index, ship_class, wep, wep_count);
1937                 } else {
1938                         // ship has been created
1939 //                      wl_get_ship_weapons(slot_num/4, slot_num%4, wep, wep_count);
1940                         int ship_index = -1;
1941                         p_object *pobjp;
1942                         ss_return_ship(slot_num/4, slot_num%4, &ship_index, &pobjp);
1943                         SDL_assert(ship_index != -1);
1944                         wl_get_ship_weapons(ship_index, wep, wep_count);
1945                 }
1946         }
1947
1948         // ensure that there aren't any bogus weapons assigned by default
1949         wl_cull_illegal_weapons(ship_class, wep, wep_count);    
1950 }
1951
1952 // function to add a weapon_class to ui lists
1953 void wl_add_index_to_list(int wi_index)
1954 {
1955         int i;
1956         if ( Weapon_info[wi_index].subtype == WP_MISSILE ) {
1957
1958                 for ( i=0; i<Slist_size; i++ ) {
1959                         if ( Slist[i] == wi_index )
1960                                 break;
1961                 }
1962
1963                 if ( i == Slist_size ) 
1964                         Slist[Slist_size++] = wi_index;
1965
1966         } else {
1967                 for ( i=0; i<Plist_size; i++ ) {
1968                         if ( Plist[i] == wi_index )
1969                                 break;
1970                 }
1971
1972                 if ( i == Plist_size ) 
1973                         Plist[Plist_size++] = wi_index;
1974         }
1975 }
1976
1977 // remove the weapons specificed by wep[] and wep_count[] from Wl_pool[].
1978 void wl_remove_weps_from_pool(int *wep, int *wep_count, int ship_class)
1979 {
1980         int i, wi_index;
1981
1982         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
1983                 wi_index = wep[i];
1984                 if ( wi_index >= 0 ) {
1985                         if ( (wep_count[i] > 0) && ((Wl_pool[wi_index] - wep_count[i]) >= 0) ) {
1986                                 Wl_pool[wi_index] -= wep_count[i];
1987                         } else {
1988                                 // not enough weapons in pool
1989                                 // TEMP HACK: FRED doesn't fill in a weapons pool if there are no starting wings... so
1990                                 //            add to the pool.  This should be fixed.
1991                                 if ( Wss_num_wings <= 0 ) {
1992                                         wl_add_index_to_list(wi_index);
1993                                 } else {
1994         
1995                                         if ( (Wl_pool[wi_index] <= 0) || (wep_count[i] == 0) ) {
1996                                                 // fresh out of this weapon, pick an alternate pool weapon if we can
1997                                                 int wep_pool_index, wep_precedence_index, new_wi_index = -1;
1998                                                 for ( wep_pool_index = 0; wep_pool_index < MAX_WEAPON_TYPES; wep_pool_index++ ) {
1999
2000                                                         if ( Wl_pool[wep_pool_index] <= 0 ) {
2001                                                                 continue;
2002                                                         }
2003
2004                                                         // AL 3-31-98: Only pick another primary if primary, etc
2005                                                         if ( Weapon_info[wi_index].subtype != Weapon_info[wep_pool_index].subtype ) {
2006                                                                 continue;
2007                                                         }
2008
2009                                                         if ( !weapon_allowed_for_game_type(Ship_info[ship_class].allowed_weapons[wep_pool_index]) ) {
2010                                                                 continue;
2011                                                         }
2012
2013
2014                                                         for ( wep_precedence_index = 0; wep_precedence_index < Num_player_weapon_precedence; wep_precedence_index++ ) {
2015                                                                 if ( wep_pool_index == Player_weapon_precedence[wep_precedence_index] ) {
2016                                                                         new_wi_index = wep_pool_index;
2017                                                                         break;
2018                                                                 }
2019                                                         }
2020
2021                                                         if ( new_wi_index >= 0 ) {
2022                                                                 break;
2023                                                         }
2024                                                 }
2025
2026                                                 if ( new_wi_index >= 0 ) {
2027                                                         wep[i] = new_wi_index;
2028                                                         wi_index = new_wi_index;
2029                                                 }
2030                                         }
2031
2032                                         int new_wep_count = wep_count[i];
2033                                         if ( Weapon_info[wi_index].subtype == WP_MISSILE ) {
2034                                                 int secondary_bank_index;
2035                                                 secondary_bank_index = i-3;
2036                                                 if ( secondary_bank_index < 0 ) {
2037                                                         Int3();
2038                                                         secondary_bank_index = 0;
2039                                                 }
2040                                                 new_wep_count = wl_calc_missile_fit(wi_index, Ship_info[ship_class].secondary_bank_ammo_capacity[secondary_bank_index]);
2041                                         }
2042
2043                                         wep_count[i] = min(new_wep_count, Wl_pool[wi_index]);
2044                                         SDL_assert(wep_count[i] >= 0);
2045                                         Wl_pool[wi_index] -= wep_count[i];
2046                                         if ( wep_count[i] <= 0 ) {
2047                                                 wep[i] = -1;
2048                                         }
2049                                 }
2050                         }
2051                 }
2052         }
2053 }
2054
2055 // Init the weapons portion of Wss_slots[] and the ui data in Wl_slots[]
2056 // NOTE: it is assumed that Wl_pool[] has been initialized, and Wss_slots[].ship_class is correctly set
2057 void wl_fill_slots()
2058 {
2059         int i, j;       
2060         int wep[MAX_WL_WEAPONS];
2061         int wep_count[MAX_WL_WEAPONS];
2062         
2063         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2064                 if ( Wss_slots[i].ship_class < 0 ){
2065                         continue;
2066                 }
2067
2068                 // get the weapons info that should be on ship by default
2069                 wl_get_default_weapons(Wss_slots[i].ship_class, i, wep, wep_count);
2070                 wl_remove_weps_from_pool(wep, wep_count, Wss_slots[i].ship_class);
2071
2072                 // copy to Wss_slots[]
2073                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
2074                         Wss_slots[i].wep[j] = wep[j];
2075                         Wss_slots[i].wep_count[j] = wep_count[j];
2076                 }
2077         }       
2078 }
2079
2080 // set up the primary and secondary icons lists that hold the weapons the player can choose from
2081 void wl_init_icon_lists()
2082 {
2083         int i;
2084
2085         Plist_start = 0;                // offset into Plist[]
2086         Slist_start = 0;
2087
2088         Plist_size = 0;         // number of active elements in Plist[]
2089         Slist_size = 0;
2090
2091         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
2092                 Plist[i] = -1;
2093                 Slist[i] = -1;
2094         }
2095
2096         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
2097                 if ( Wl_pool[i] > 0 ) {
2098                         if ( Weapon_info[i].subtype == WP_MISSILE ) {
2099                                 Slist[Slist_size++] = i;
2100                         } else {
2101                                 Plist[Plist_size++] = i;
2102                         }
2103                 }
2104         }
2105 }
2106
2107 // initialize team specific weapon select data structures
2108 void weapon_select_init_team(int team_num)
2109 {
2110         Wl_icons = Wl_icons_teams[team_num];
2111         ss_set_team_pointers(team_num);
2112
2113         wl_init_pool(&Team_data[team_num]);
2114         wl_init_icon_lists();
2115         wl_init_ship_class_data();
2116
2117         wl_load_all_icons();
2118         wl_load_all_anims();
2119
2120         wl_fill_slots();
2121 }
2122
2123 // close out what weapon_select_init_team() set up but only when we are not acutally
2124 // in the weapon select screen
2125 void weapon_select_close_team()
2126 {
2127         if (Weapon_select_open)
2128                 return;
2129
2130         wl_unload_all_anim_instances();
2131         wl_unload_all_anims();
2132 }
2133
2134 // This init is called even before the weapons loadout screen is entered.  It is called when the
2135 // briefing state is entered.
2136 void weapon_select_common_init()
2137 {
2138         int idx;
2139         
2140         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2141                 // initialize for all teams
2142                 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
2143                         weapon_select_init_team(idx);
2144                 }
2145
2146                 // re-initialize for me specifically
2147                 weapon_select_init_team(Common_team);
2148         } else {        
2149                 // initialize for my own team
2150                 weapon_select_init_team(Common_team);
2151         }
2152
2153         wl_reset_selected_slot();
2154         wl_reset_carried_icon();
2155         wl_maybe_reset_selected_weapon_class();
2156 }
2157
2158 // ---------------------------------------------------------------------------------
2159 // weapon_select_init() is called to load the bitmaps and set up the mask regions for
2160 //      the weapon loadout screen.  common_select_init() is called to load the animations
2161 // and bitmaps which are in common with the ship select and briefing screens.
2162 //
2163 // The Weapon_select_open flag is set to 1 when weapon_select_init() completes successfully
2164 //
2165 void weapon_select_init()
2166 {
2167         common_set_interface_palette("WeaponPalette");
2168         common_flash_button_init();
2169
2170         // for multiplayer, change the state in my netplayer structure
2171         if ( Game_mode & GM_MULTIPLAYER )
2172                 Net_player->state = NETPLAYER_STATE_WEAPON_SELECT;
2173
2174         ship_stop_animation();
2175         stop_weapon_animation();
2176         Weapon_anim_class = -1;
2177
2178         set_active_ui(&Weapon_ui_window);
2179         Current_screen = ON_WEAPON_SELECT;
2180         Last_wl_ship_class = -1;
2181
2182         wl_maybe_reset_selected_slot();
2183         wl_set_disabled_weapons(Wss_slots[Selected_wl_slot].ship_class);
2184
2185         help_overlay_set_state(WL_OVERLAY,0);
2186
2187         if ( Weapon_select_open ) {
2188                 wl_maybe_reset_selected_weapon_class();
2189                 wl_start_slot_animation(Selected_wl_slot);
2190                 common_buttons_maybe_reload(&Weapon_ui_window); // AL 11-21-97: this is necessary since we may returning from the hotkey
2191                                                                                                                                                 // screen, which can release common button bitmaps.
2192                 common_reset_buttons();
2193                 nprintf(("Alan","weapon_select_init() returning without doing anything\n"));
2194
2195                 // if we're in multiplayer always select the player's ship
2196                 wl_reset_selected_slot();
2197
2198                 return;
2199         }
2200
2201         nprintf(("Alan","entering weapon_select_init()\n"));
2202         common_select_init();
2203         
2204         WeaponSelectMaskBitmap = bm_load(Wl_loadout_select_mask[gr_screen.res]);
2205         if (WeaponSelectMaskBitmap < 0) {
2206                 if (gr_screen.res == GR_640) {
2207                         Error(LOCATION,"Could not load in 'weaponloadout-m'!");
2208                 } else if (gr_screen.res == GR_1024) {
2209                         Error(LOCATION,"Could not load in '2_weaponloadout-m'!");
2210                 } else {
2211                         Error(LOCATION,"Could not load in 'weaponloadout-m'!");
2212                 }
2213         }
2214
2215         Weaponselect_mask_w = -1;
2216         Weaponselect_mask_h = -1;
2217
2218         // get a pointer to bitmap by using bm_lock()
2219         WeaponSelectMaskPtr = bm_lock(WeaponSelectMaskBitmap, 8, BMP_AABITMAP);
2220         WeaponSelectMaskData = (ubyte*)WeaponSelectMaskPtr->data;
2221         SDL_assert(WeaponSelectMaskData != NULL);
2222         bm_get_info(WeaponSelectMaskBitmap, &Weaponselect_mask_w, &Weaponselect_mask_h);
2223
2224
2225         // Set up the mask regions
2226    // initialize the different regions of the menu that will react when the mouse moves over it
2227         Num_weapon_select_regions = 0;
2228         
2229         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_BRIEFING_REGION,                         0);
2230         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_SS_REGION,                                               0);
2231         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_WEAPON_REGION,                           0);
2232         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_COMMIT_REGION,                           0);
2233         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_HELP_REGION,                                     0);
2234         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  COMMON_OPTIONS_REGION,                          0);
2235
2236         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_0_SHIP_0,          0);
2237         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_0_SHIP_1,          0);
2238         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_0_SHIP_2,          0);
2239         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_0_SHIP_3,          0);
2240         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_1_SHIP_0,          0);
2241         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_1_SHIP_1,          0);
2242         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_1_SHIP_2,          0);
2243         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_1_SHIP_3,          0);
2244         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_2_SHIP_0,          0);
2245         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_2_SHIP_1,          0);
2246         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_2_SHIP_2,          0);
2247         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  WING_2_SHIP_3,          0);
2248
2249         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_PRIMARY_0,         0);
2250         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_PRIMARY_1,         0);
2251         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_PRIMARY_2,         0);
2252         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_PRIMARY_3,         0);
2253         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SECONDARY_0,               0);
2254         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SECONDARY_1,               0);
2255         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SECONDARY_2,               0);
2256         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SECONDARY_3,               0);
2257
2258         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_PRIMARY_0,            0);
2259         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_PRIMARY_1,            0);
2260         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_PRIMARY_2,            0);
2261         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_SECONDARY_0,          0);
2262         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_SECONDARY_1,          0);
2263         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_SECONDARY_2,          0);
2264         snazzy_menu_add_region(&Weapon_select_region[Num_weapon_select_regions++], "",  ICON_SHIP_SECONDARY_3,          0);
2265
2266         // init common UI
2267         Weapon_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
2268
2269         if(Game_mode & GM_MULTIPLAYER){
2270                 Weapon_ui_window.set_mask_bmap(Wl_mask_multi[gr_screen.res]);
2271         } else {
2272                 Weapon_ui_window.set_mask_bmap(Wl_mask_single[gr_screen.res]);
2273         }
2274
2275         // initialize background bitmap
2276         if(Game_mode & GM_MULTIPLAYER) {
2277                 Weapon_select_background_bitmap = bm_load(Weapon_select_multi_background_fname[gr_screen.res]);
2278         } else {
2279                 Weapon_select_background_bitmap = bm_load(Weapon_select_background_fname[gr_screen.res]);
2280         }
2281
2282         Weapon_ui_window.tooltip_handler = wl_tooltip_handler;
2283         common_buttons_init(&Weapon_ui_window);
2284         weapon_buttons_init();
2285         Weapon_select_open = 1;
2286
2287         // if we're in multiplayer always select the player's ship
2288         wl_reset_selected_slot();
2289 }
2290
2291 // ----------------------------------------------------------------
2292 // wl_dump_carried_icon()
2293 void wl_dump_carried_icon()
2294 {
2295         if ( wl_icon_being_carried() ) {
2296                 // Add back into the weapon pool
2297                 if ( Carried_wl_icon.from_bank >= 0 ) {
2298                         // return to list
2299                         wl_drop(Carried_wl_icon.from_bank, -1, -1, Carried_wl_icon.weapon_class, Carried_wl_icon.from_slot);
2300                 } else {
2301                         if ( wl_carried_icon_moved() ) {
2302                                 gamesnd_play_iface(SND_ICON_DROP);
2303                         }                       
2304                 }
2305
2306                 wl_reset_carried_icon();
2307         }
2308 }
2309
2310 // ----------------------------------------------------------------
2311 // drop_icon_on_slot()
2312 //
2313 // Drop the Carried_wl_icon onto the specified slot.  The slot numbering is:
2314 //
2315 // 0->2: primary weapons
2316 // 3-6: secondary weapons
2317 //
2318 // These are the slots that exist beside the overhead view of the ship.
2319 // on the weapons loadout screen.
2320 //
2321 int drop_icon_on_slot(int bank_num)
2322 {
2323         if ( Selected_wl_slot == -1 ) {
2324                 return 0;
2325         }
2326
2327         if(Game_mode & GM_MULTIPLAYER){
2328                 if(multi_ts_disabled_slot(Selected_wl_slot)){
2329                         return 0;
2330                 }
2331         } else {
2332                 if ( ss_disabled_slot( Selected_wl_slot ) ){
2333                         return 0;
2334                 }
2335         }
2336
2337         // check if slot exists
2338         if ( Wss_slots[Selected_wl_slot].wep_count[bank_num] < 0 ) {
2339                 return 0;
2340         }
2341
2342         if ( !wl_carried_icon_moved() ) {
2343                 wl_reset_carried_icon();
2344                 return 0;
2345         }
2346
2347         wl_drop(Carried_wl_icon.from_bank, Carried_wl_icon.weapon_class, bank_num, -1, Selected_wl_slot);
2348         return 1;
2349 }
2350
2351 // ----------------------------------------------------------------
2352 // maybe_drop_icon_on_slot()
2353 //
2354 void maybe_drop_icon_on_slot(int bank_num)
2355 {
2356         int dropped=0;
2357         if ( !mouse_down(MOUSE_LEFT_BUTTON) ) {
2358                 if ( wl_icon_being_carried() )
2359                         dropped = drop_icon_on_slot(bank_num);
2360
2361                 if ( dropped ) {
2362                         wl_reset_carried_icon();
2363                 }
2364         }
2365 }               
2366
2367 // ----------------------------------------------------------------
2368 // wl_check_for_stopped_ship_anims()
2369 //
2370 void wl_check_for_stopped_ship_anims()
2371 {
2372         int i;
2373         anim_instance *ai;
2374         for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2375                 ai = Wl_ships[i].anim_instance;
2376                 if ( ai != NULL ) {
2377                         if ( !anim_playing(ai) ) {
2378                                 Wl_ships[i].anim_instance = NULL;
2379                         }
2380                 }
2381         }
2382 }
2383
2384 // ---------------------------------------------------------------------------------
2385 // do_mouse_over_list_weapon()
2386 //
2387 void do_mouse_over_list_weapon(int index)
2388 {
2389         Hot_weapon_icon = index;
2390
2391         int region_index = ICON_PRIMARY_0+index;
2392         if ( index > 3 ) {
2393                 region_index = ICON_SECONDARY_0 + (index - 4);
2394         }
2395         
2396         if ( Wl_mouse_down_on_region != region_index ){
2397                 return;
2398         }
2399
2400         if ( mouse_down(MOUSE_LEFT_BUTTON) )
2401                 wl_pick_icon_from_list(index);
2402 }
2403
2404 // ---------------------------------------------------------------------------------
2405 // do_mouse_over_ship_weapon()
2406 //
2407 //
2408 // input: index -> bank index on ship (0..6)
2409 //
2410 // returns: 
2411 //          0 -> icon was not dropped on a slot
2412 //                              1 -> icon was dropped on a slot
2413 int do_mouse_over_ship_weapon(int index)
2414 {
2415         int dropped_on_slot, is_moved, mx, my;
2416
2417         dropped_on_slot = 0;
2418         SDL_assert(Selected_wl_slot >= 0);
2419
2420         if ( ss_disabled_slot( Selected_wl_slot ) )
2421                 return 0;
2422
2423         Hot_weapon_bank_icon = index;   // bank icon will be drawn highlighted
2424
2425         if ( mouse_down(MOUSE_LEFT_BUTTON) ) {
2426                 if ( Wl_mouse_down_on_region == (ICON_SHIP_PRIMARY_0+index) ){
2427                         pick_from_ship_slot(index);
2428                 }
2429         } else {
2430                 int was_carried = wl_icon_being_carried();
2431                 maybe_drop_icon_on_slot(index);
2432                 if ( was_carried && !wl_icon_being_carried() ) {
2433                         mouse_get_pos( &mx, &my );
2434                         if ( Carried_wl_icon.from_x != mx || Carried_wl_icon.from_y != my) {
2435                                 dropped_on_slot = 1;
2436                         }
2437                 }
2438         }
2439
2440         // set Hot_weapon_bank if a droppable icon is being held over a slot that
2441         // can accept that icon
2442         is_moved = 0;
2443         mouse_get_pos( &mx, &my );
2444         if ( Carried_wl_icon.from_x != mx || Carried_wl_icon.from_y != my) {
2445                 is_moved = 1;
2446         }
2447
2448         if ( wl_icon_being_carried() && is_moved ) {
2449                 if ( Weapon_info[Carried_wl_icon.weapon_class].subtype != WP_MISSILE ) {
2450                         if ( (index < 3) && (Wss_slots[Selected_wl_slot].wep_count[index] >= 0) ) 
2451                                 Hot_weapon_bank = index;
2452                 } else {
2453                         if ( index >= 3 && ( Wss_slots[Selected_wl_slot].wep_count[index] >= 0) ) 
2454                                 Hot_weapon_bank = index;
2455                 }
2456         }
2457
2458         return dropped_on_slot;
2459 }
2460
2461
2462 // maybe flash a button if player hasn't done anything for a while
2463 void wl_maybe_flash_button()
2464 {
2465         if ( common_flash_bright() ) {
2466                 // commit button
2467                 if ( Common_buttons[Current_screen-1][gr_screen.res][3].button.button_hilighted() ) {
2468                         common_flash_button_init();
2469                 } else {
2470                         Common_buttons[Current_screen-1][gr_screen.res][3].button.draw_forced(1);
2471                 }
2472         }
2473 }
2474
2475
2476 void weapon_select_render(float frametime)
2477 {
2478         if ( !Background_playing ) {
2479                 gr_set_bitmap(Weapon_select_background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2480                 gr_bitmap(0, 0);
2481         }
2482
2483         anim_render_all(0, frametime);
2484         anim_render_all(ON_SHIP_SELECT, frametime);
2485 }
2486
2487 // draw the weapon description text
2488 // this wipes in
2489 void wl_render_weapon_desc(float frametime)
2490 {
2491 #ifndef MAKE_FS1
2492         int *weapon_desc_coords;
2493         int *weapon_title_coords;
2494
2495         // retrieve the correct set of text coordinates
2496         if (Game_mode & GM_MULTIPLAYER) {
2497                 weapon_desc_coords = Wl_new_weapon_desc_coords_multi[gr_screen.res];
2498                 weapon_title_coords = Wl_new_weapon_title_coords_multi[gr_screen.res];
2499         } else {
2500                 weapon_desc_coords = Wl_new_weapon_desc_coords[gr_screen.res];
2501                 weapon_title_coords = Wl_new_weapon_title_coords[gr_screen.res];
2502         }
2503
2504         // render the normal version of the weapom desc
2505         char bright_char[WEAPON_DESC_MAX_LINES];                        // one bright char per line
2506         if (!Weapon_desc_wipe_done) {
2507                 // draw mid-wipe version
2508                 // decide which char is last (and bright)
2509                 int bright_char_index = (int)(Weapon_desc_wipe_time_elapsed * WEAPON_DESC_MAX_LENGTH / WEAPON_DESC_WIPE_TIME);
2510                 int i, w, h, curr_len;
2511                 
2512                 // draw weapon title (above weapon anim)
2513                 for (i=0; i<2; i++) {
2514                         curr_len = strlen(Weapon_desc_lines[i]);
2515
2516                         if (bright_char_index < curr_len) {
2517                                 // save bright char and plunk in some nulls to shorten string
2518                                 bright_char[i] = Weapon_desc_lines[i][bright_char_index];
2519                                 Weapon_desc_lines[i][bright_char_index] = '\0';
2520
2521                                 // draw the strings
2522                                 gr_set_color_fast(&Color_white);                        
2523                                 gr_string(weapon_title_coords[0], weapon_title_coords[1]+(10*i), Weapon_desc_lines[i]);
2524
2525                                 // draw the bright letters
2526                                 gr_set_color_fast(&Color_bright_white);
2527                                 gr_get_string_size(&w, &h, Weapon_desc_lines[i], curr_len);
2528                                 gr_printf(weapon_title_coords[0]+w, weapon_title_coords[1]+(10*i), "%c", bright_char[i]);
2529
2530                                 // restore the bright char to the string
2531                                 Weapon_desc_lines[i][bright_char_index] = bright_char[i];
2532
2533                         } else {
2534                                 // draw the string
2535                                 gr_set_color_fast(&Color_white);
2536                                 gr_string(weapon_title_coords[0], weapon_title_coords[1]+(10*i), Weapon_desc_lines[i]);
2537                         }
2538                 }
2539
2540                 // draw weapon desc (below weapon anim)
2541                 for (i=2; i<WEAPON_DESC_MAX_LINES; i++) {
2542                         curr_len = strlen(Weapon_desc_lines[i]);
2543
2544                         if (bright_char_index < curr_len) {
2545                                 // save bright char and plunk in some nulls to shorten string
2546                                 bright_char[i] = Weapon_desc_lines[i][bright_char_index];
2547                                 Weapon_desc_lines[i][bright_char_index] = '\0';
2548
2549                                 // draw the string
2550                                 gr_set_color_fast(&Color_white);
2551                                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1]+(10*(i-2)), Weapon_desc_lines[i]);
2552
2553                                 // draw the bright letters
2554                                 gr_set_color_fast(&Color_bright_white);
2555                                 gr_get_string_size(&w, &h, Weapon_desc_lines[i], curr_len);
2556                                 gr_printf(weapon_desc_coords[0]+w, weapon_desc_coords[1]+(10*(i-2)), "%c", bright_char[i]);
2557
2558                                 // restore the bright char to the string
2559                                 Weapon_desc_lines[i][bright_char_index] = bright_char[i];
2560
2561                         } else {
2562                                 // draw the string
2563                                 gr_set_color_fast(&Color_white);
2564                                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1]+(10*(i-2)), Weapon_desc_lines[i]);
2565                         }
2566                 }
2567
2568                 // update time
2569                 Weapon_desc_wipe_time_elapsed += frametime;
2570                 if (Weapon_desc_wipe_time_elapsed >= WEAPON_DESC_WIPE_TIME) {
2571                         // wipe is done,set flag and stop sound
2572                         Weapon_desc_wipe_done = 1;
2573                 }
2574
2575         } else {
2576
2577                 // draw full version
2578                 // FIXME - change to use a for loop 
2579                 gr_set_color_fast(&Color_white);
2580                 gr_string(weapon_title_coords[0], weapon_title_coords[1], Weapon_desc_lines[0]);
2581                 gr_string(weapon_title_coords[0], weapon_title_coords[1] + 10, Weapon_desc_lines[1]);
2582                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1], Weapon_desc_lines[2]);
2583                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1] + 10, Weapon_desc_lines[3]);
2584                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1] + 20, Weapon_desc_lines[4]);
2585                 gr_string(weapon_desc_coords[0], weapon_desc_coords[1] + 30, Weapon_desc_lines[5]);
2586         }
2587 #endif
2588 }
2589
2590
2591
2592 // re-inits wiping vars and causes the current text to wipe in again
2593 void wl_weapon_desc_start_wipe()
2594 {
2595 #ifndef MAKE_FS1
2596         int currchar_src = 0, currline_dest = 2, currchar_dest = 0, i;
2597         int w, h;
2598         int title_len = strlen(Weapon_info[Selected_wl_class].title);
2599
2600         // init wipe vars
2601         Weapon_desc_wipe_time_elapsed = 0.0f;
2602         Weapon_desc_wipe_done = 0;
2603
2604         // break title into two lines if too long
2605         SDL_strlcpy(Weapon_desc_lines[0], Weapon_info[Selected_wl_class].title, WEAPON_DESC_MAX_LENGTH);
2606         gr_get_string_size(&w, &h, Weapon_info[Selected_wl_class].title, title_len);
2607         if (w > Weapon_title_max_width[gr_screen.res]) {
2608                 // split
2609                 currchar_src = (int)(((float)title_len / (float)w) * Weapon_title_max_width[gr_screen.res]);                    // char to start space search at
2610                 while (Weapon_desc_lines[0][currchar_src] != ' ') {
2611                         currchar_src--;
2612                         if (currchar_src <= 0) {
2613                                 currchar_src = title_len;
2614                                 break;
2615                         }
2616                 }
2617
2618                 Weapon_desc_lines[0][currchar_src] = '\0';                                                                              // shorten line 0
2619                 SDL_strlcpy(Weapon_desc_lines[1], &(Weapon_desc_lines[0][currchar_src+1]), WEAPON_DESC_MAX_LENGTH);             // copy remainder into line 1
2620         } else {
2621                 // entire title in line 0, thus line 1 is empty
2622                 Weapon_desc_lines[1][0] = '\0';
2623         }
2624         
2625         // break current description into lines (break at the /n's)
2626         currchar_src = 0;
2627         while (Weapon_info[Selected_wl_class].desc[currchar_src] != '\0') {
2628                 if (Weapon_info[Selected_wl_class].desc[currchar_src] == '\n') {
2629                         // break here
2630                         if (currchar_src != 0) {                                        // protect against leading /n's
2631                                 Weapon_desc_lines[currline_dest][currchar_dest] = '\0';
2632                                 currline_dest++;
2633                                 currchar_dest = 0;
2634                         }
2635                 } else {
2636                         // straight copy
2637                         Weapon_desc_lines[currline_dest][currchar_dest] = Weapon_info[Selected_wl_class].desc[currchar_src];
2638                         currchar_dest++;
2639                 }
2640
2641                 currchar_src++;
2642
2643                 SDL_assert(currline_dest < WEAPON_DESC_MAX_LINES);
2644                 SDL_assert(currchar_dest < WEAPON_DESC_MAX_LENGTH);
2645         }
2646
2647         // wrap up the line processing
2648         Weapon_desc_lines[currline_dest][currchar_dest] = '\0';
2649         for (i=currline_dest+1; i<WEAPON_DESC_MAX_LINES; i++) {
2650                 Weapon_desc_lines[i][0] = '\0';
2651         }
2652 #endif
2653 }
2654
2655
2656
2657 // ---------------------------------------------------------------------------------
2658 // weapon_select_do() is called once per frame while in the weapon loadout screen.  
2659 //
2660 // Calls to common_ functions are made for those functions which are common to the
2661 // ship select and briefing screens.
2662 //
2663 void weapon_select_do(float frametime)
2664 {
2665         int k, wl_choice, snazzy_action;
2666         //char buf[256];
2667
2668         if ( !Weapon_select_open )
2669                 weapon_select_init();
2670
2671         wl_choice = snazzy_menu_do(WeaponSelectMaskData, Weaponselect_mask_w, Weaponselect_mask_h, Num_weapon_select_regions, Weapon_select_region, &snazzy_action, 0);
2672
2673         if ( wl_choice >= 0 ) {
2674                 if ( snazzy_action == SNAZZY_CLICKED ) {
2675                         nprintf(("Alan","got one\n"));
2676                 } 
2677         }
2678
2679         Hot_wl_slot = -1;
2680         Hot_weapon_icon = -1;
2681         Hot_weapon_bank = -1;
2682         Hot_weapon_bank_icon = -1;
2683
2684         k = common_select_do(frametime);
2685         
2686         if ( help_overlay_active(WL_OVERLAY) ) {
2687                 if ( Weapon_anim_class >= 0 && Wl_icons[Weapon_anim_class].anim_instance ) {
2688                         anim_pause(Wl_icons[Weapon_anim_class].anim_instance);
2689                 }
2690         }
2691         else {
2692                 if ( Weapon_anim_class >= 0 && Wl_icons[Weapon_anim_class].anim_instance ) {
2693                         anim_unpause(Wl_icons[Weapon_anim_class].anim_instance);
2694                 }
2695         }
2696
2697         // Check common keypresses
2698         common_check_keys(k);
2699
2700         if ( Mouse_down_last_frame ) {
2701                 Wl_mouse_down_on_region = wl_choice;
2702         }
2703
2704         if ( wl_choice > -1 ) {
2705                 switch(wl_choice) {
2706                         case ICON_PRIMARY_0:
2707                                 do_mouse_over_list_weapon(0);
2708                                 break;
2709                         case ICON_PRIMARY_1:
2710                                 do_mouse_over_list_weapon(1);
2711                                 break;
2712                         case ICON_PRIMARY_2:
2713                                 do_mouse_over_list_weapon(2);
2714                                 break;
2715                         case ICON_PRIMARY_3:
2716                                 do_mouse_over_list_weapon(3);
2717                                 break;
2718                         case ICON_SECONDARY_0:
2719                                 do_mouse_over_list_weapon(4);
2720                                 break;
2721                         case ICON_SECONDARY_1:
2722                                 do_mouse_over_list_weapon(5);
2723                                 break;
2724                         case ICON_SECONDARY_2:
2725                                 do_mouse_over_list_weapon(6);
2726                                 break;
2727                         case ICON_SECONDARY_3:
2728                                 do_mouse_over_list_weapon(7);
2729                                 break;
2730                         case ICON_SHIP_PRIMARY_0:
2731                                 if ( do_mouse_over_ship_weapon(0) )
2732                                         wl_choice = -1;
2733                                 break;
2734                         case ICON_SHIP_PRIMARY_1:
2735                                 if ( do_mouse_over_ship_weapon(1) )
2736                                         wl_choice = -1;
2737                                 break;
2738                         case ICON_SHIP_PRIMARY_2:
2739                                 if ( do_mouse_over_ship_weapon(2) )
2740                                         wl_choice = -1;
2741                                 break;
2742                         case ICON_SHIP_SECONDARY_0:
2743                                 if ( do_mouse_over_ship_weapon(3) )
2744                                         wl_choice = -1;
2745                                 break;
2746                         case ICON_SHIP_SECONDARY_1:
2747                                 if ( do_mouse_over_ship_weapon(4) )
2748                                         wl_choice = -1;
2749                                 break;
2750                         case ICON_SHIP_SECONDARY_2:
2751                                 if ( do_mouse_over_ship_weapon(5) )
2752                                         wl_choice = -1;
2753                                 break;
2754                         case ICON_SHIP_SECONDARY_3:
2755                                 if ( do_mouse_over_ship_weapon(6) )
2756                                         wl_choice = -1;
2757                                 break;
2758                         case WING_0_SHIP_0:
2759                                 Hot_wl_slot = 0;
2760                                 break;
2761                         case WING_0_SHIP_1:
2762                                 Hot_wl_slot = 1;
2763                                 break;
2764                         case WING_0_SHIP_2:
2765                                 Hot_wl_slot = 2;
2766                                 break;
2767                         case WING_0_SHIP_3:
2768                                 Hot_wl_slot = 3;
2769                                 break;
2770                         case WING_1_SHIP_0:
2771                                 Hot_wl_slot = 4;
2772                                 break;
2773                         case WING_1_SHIP_1:
2774                                 Hot_wl_slot = 5;
2775                                 break;
2776                         case WING_1_SHIP_2:
2777                                 Hot_wl_slot = 6;
2778                                 break;
2779                         case WING_1_SHIP_3:
2780                                 Hot_wl_slot = 7;
2781                                 break;
2782                         case WING_2_SHIP_0:
2783                                 Hot_wl_slot = 8;
2784                                 break;
2785                         case WING_2_SHIP_1:
2786                                 Hot_wl_slot = 9;
2787                                 break;
2788                         case WING_2_SHIP_2:
2789                                 Hot_wl_slot = 10;
2790                                 break;
2791                         case WING_2_SHIP_3:
2792                                 Hot_wl_slot = 11;
2793                                 break;
2794
2795                         default:
2796                                 break;
2797                 }       // end switch
2798         }
2799
2800         if ( !mouse_down(MOUSE_LEFT_BUTTON) )  {
2801                 wl_dump_carried_icon();
2802         }
2803
2804         // Check for a mouse click on buttons
2805         common_check_buttons();
2806         weapon_check_buttons();
2807
2808         // Check for the mouse clicks over a region
2809         if ( wl_choice > -1 && snazzy_action == SNAZZY_CLICKED ) {
2810                 switch (wl_choice) {
2811                                 case ICON_PRIMARY_0:
2812                                         maybe_select_new_weapon(0);
2813                                         break;
2814                                 case ICON_PRIMARY_1:
2815                                         maybe_select_new_weapon(1);
2816                                         break;
2817                                 case ICON_PRIMARY_2:
2818                                         maybe_select_new_weapon(2);
2819                                         break;
2820                                 case ICON_PRIMARY_3:
2821                                         maybe_select_new_weapon(3);
2822                                         break;
2823                                 case ICON_SECONDARY_0:
2824                                         maybe_select_new_weapon(4);
2825                                         break;
2826                                 case ICON_SECONDARY_1:
2827                                         maybe_select_new_weapon(5);
2828                                         break;
2829                                 case ICON_SECONDARY_2:
2830                                         maybe_select_new_weapon(6);
2831                                         break;
2832                                 case ICON_SECONDARY_3:
2833                                         maybe_select_new_weapon(7);
2834                                         break;
2835                                 case ICON_SHIP_PRIMARY_0:
2836                                         maybe_select_new_ship_weapon(0);
2837                                         break;
2838                                 case ICON_SHIP_PRIMARY_1:
2839                                         maybe_select_new_ship_weapon(1);
2840                                         break;
2841                                 case ICON_SHIP_PRIMARY_2:
2842                                         maybe_select_new_ship_weapon(2);
2843                                         break;
2844                                 case ICON_SHIP_SECONDARY_0:
2845                                         maybe_select_new_ship_weapon(3);
2846                                         break;
2847                                 case ICON_SHIP_SECONDARY_1:
2848                                         maybe_select_new_ship_weapon(4);
2849                                         break;
2850                                 case ICON_SHIP_SECONDARY_2:
2851                                         maybe_select_new_ship_weapon(5);
2852                                         break;
2853                                 case ICON_SHIP_SECONDARY_3:
2854                                         maybe_select_new_ship_weapon(6);
2855                                         break;
2856                                 case WING_0_SHIP_0:
2857                                         maybe_select_wl_slot(0,0);
2858                                         break;
2859                                 case WING_0_SHIP_1:
2860                                         maybe_select_wl_slot(0,1);
2861                                         break;
2862                                 case WING_0_SHIP_2:
2863                                         maybe_select_wl_slot(0,2);
2864                                         break;
2865                                 case WING_0_SHIP_3:
2866                                         maybe_select_wl_slot(0,3);
2867                                         break;
2868                                 case WING_1_SHIP_0:
2869                                         maybe_select_wl_slot(1,0);
2870                                         break;
2871                                 case WING_1_SHIP_1:
2872                                         maybe_select_wl_slot(1,1);
2873                                         break;
2874                                 case WING_1_SHIP_2:
2875                                         maybe_select_wl_slot(1,2);
2876                                         break;
2877                                 case WING_1_SHIP_3:
2878                                         maybe_select_wl_slot(1,3);
2879                                         break;
2880                                 case WING_2_SHIP_0:
2881                                         maybe_select_wl_slot(2,0);
2882                                         break;
2883                                 case WING_2_SHIP_1:
2884                                         maybe_select_wl_slot(2,1);
2885                                         break;
2886                                 case WING_2_SHIP_2:
2887                                         maybe_select_wl_slot(2,2);
2888                                         break;
2889                                 case WING_2_SHIP_3:
2890                                         maybe_select_wl_slot(2,3);
2891                                         break;
2892
2893                                 default:
2894                                         break;
2895
2896                         }       // end switch
2897                 }
2898
2899         gr_reset_clip();
2900
2901         if ( Weapon_anim_class != -1 && ( Selected_wl_class == Weapon_anim_class ) ) {
2902                 wl_icon_info *icon;
2903                 SDL_assert(Selected_wl_class >= 0 && Selected_wl_class < MAX_WEAPON_TYPES );
2904                 if ( Weapon_anim_class != Selected_wl_class ) 
2905                         start_weapon_animation(Selected_wl_class);      
2906
2907                 SDL_assert(Weapon_anim_class == Selected_wl_class);
2908                 icon = &Wl_icons[Selected_wl_class];
2909                 if ( icon->anim_instance ) {
2910                         if ( icon->anim_instance->frame_num == icon->anim_instance->stop_at ) {
2911                                 anim_play_struct aps;
2912                                 int *weapon_ani_coords;
2913
2914                                 // get the correct weapon animations coords
2915                                 if (Game_mode & GM_MULTIPLAYER) {
2916                                         weapon_ani_coords = Wl_weapon_ani_coords_multi[gr_screen.res];
2917                                 } else {
2918                                         weapon_ani_coords = Wl_weapon_ani_coords[gr_screen.res];
2919                                 }
2920
2921                                 anim_release_render_instance(icon->anim_instance);
2922                                 anim_play_init(&aps, icon->anim, weapon_ani_coords[0], weapon_ani_coords[1]);
2923                                 aps.start_at = WEAPON_ANIM_LOOP_FRAME-1;
2924                                 aps.screen_id = ON_WEAPON_SELECT;
2925                                 aps.framerate_independent = 1;
2926                                 aps.skip_frames = 0;
2927                                 icon->anim_instance = anim_play(&aps);
2928                         }
2929                 }
2930         }
2931
2932         weapon_select_render(frametime);
2933         if ( !Background_playing ) {            
2934                 Weapon_ui_window.draw();
2935                 wl_redraw_pressed_buttons();
2936                 draw_wl_icons();
2937                 anim_render_all(ON_WEAPON_SELECT, frametime);
2938                 wl_check_for_stopped_ship_anims();
2939                 wl_render_overhead_view(frametime);
2940                 wl_draw_ship_weapons(Selected_wl_slot);
2941                 for ( int i = 0; i < MAX_WING_BLOCKS; i++ ) {
2942                         draw_wing_block(i, Hot_wl_slot, Selected_wl_slot, -1);
2943                 }
2944                 common_render_selected_screen_button();
2945         }
2946
2947         // maybe blit the multiplayer "locked" button
2948         if((Game_mode & GM_MULTIPLAYER) && multi_ts_is_locked()){
2949                 Buttons[gr_screen.res][WL_BUTTON_MULTI_LOCK].button.draw_forced(2);
2950         }
2951
2952
2953         if ( wl_icon_being_carried() ) {
2954                 int mx, my, sx, sy;
2955                 SDL_assert(Carried_wl_icon.weapon_class < MAX_WEAPON_TYPES);
2956                 mouse_get_pos( &mx, &my );
2957                 sx = mx + Wl_delta_x;
2958                 sy = my + Wl_delta_y;
2959
2960
2961                 if ( Wl_icons[Carried_wl_icon.weapon_class].can_use > 0) {
2962                         gr_set_color_fast(&Color_blue);
2963                         gr_set_bitmap(Wl_icons[Carried_wl_icon.weapon_class].icon_bmaps[WEAPON_ICON_FRAME_SELECTED], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2964                         gr_bitmap(sx, sy);
2965                 }
2966
2967                 // draw number to prevent it from disappearing on clicks
2968                 if ( Carried_wl_icon.from_bank >= MAX_WL_PRIMARY ) {
2969                         if ( mx == Carried_wl_icon.from_x && my == Carried_wl_icon.from_y ) {
2970                                 int num_missiles = Wss_slots[Carried_wl_icon.from_slot].wep_count[Carried_wl_icon.from_bank];
2971                                 //sprintf(buf, "%d", num_missiles);
2972                                 //gr_set_color_fast(&Color_white);
2973
2974                                 //int x_offset = wl_fury_missile_offset_hack(Carried_wl_icon.weapon_class, num_missiles);
2975                                 //gr_string(sx-19-x_offset, sy+8, buf);
2976
2977
2978                                 wl_render_icon_count(num_missiles, Wl_bank_coords[gr_screen.res][Carried_wl_icon.from_bank][0], Wl_bank_coords[gr_screen.res][Carried_wl_icon.from_bank][1]);
2979                         }
2980                 }
2981
2982                 // check so see if this is really a legal weapon to carry away
2983                 if ( !Wl_icons[Carried_wl_icon.weapon_class].can_use ) {
2984                         int diffx, diffy;
2985                         diffx = abs(Carried_wl_icon.from_x-mx);
2986                         diffy = abs(Carried_wl_icon.from_y-my);
2987                         if ( (diffx > 2) || (diffy > 2) ) {
2988                                 int ship_class = Wss_slots[Selected_wl_slot].ship_class;
2989                                 wl_pause_anim();
2990                                 if (Lcl_gr) {
2991                                         // might have to get weapon name translation
2992                                         char display_name[128];
2993                                         SDL_strlcpy(display_name, Weapon_info[Carried_wl_icon.weapon_class].name, SDL_arraysize(display_name));
2994                                         lcl_translate_wep_name(display_name, SDL_arraysize(display_name));
2995                                         popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "A %s is unable to carry %s weaponry", 633), Ship_info[ship_class].name, display_name);
2996                                 } else {
2997                                         popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "A %s is unable to carry %s weaponry", 633), Ship_info[ship_class].name, Weapon_info[Carried_wl_icon.weapon_class].name);
2998                                 }
2999                                 wl_unpause_anim();
3000                                 wl_dump_carried_icon();
3001                         }
3002                 }
3003         }
3004
3005         if ( Weapon_anim_class != Selected_wl_class ) {
3006                 start_weapon_animation(Selected_wl_class);
3007         }
3008
3009         // render weapon description text
3010         wl_render_weapon_desc(frametime);
3011
3012         wl_maybe_flash_button();
3013
3014         // should render the chatbox as close to the end as possible so it overlaps all controls
3015         if(!Background_playing){
3016
3017                 // render some extra stuff in multiplayer
3018                 if(Game_mode & GM_MULTIPLAYER){                         
3019                         // render the chatbox
3020                         chatbox_render();
3021
3022                         // draw tooltips
3023                         Weapon_ui_window.draw_tooltip();
3024
3025                         // render the status indicator for the voice system
3026                         multi_common_voice_display_status();
3027
3028                         // blit the "ships/players" locked button
3029                         // multi_ts_blit_locked_button();
3030                 }
3031         }
3032
3033         // blit help overlay if active
3034         help_overlay_maybe_blit(WL_OVERLAY);
3035         gr_flip();      
3036
3037         // If the commit button was pressed, do the commit button actions.  Done at the end of the
3038         // loop so there isn't a skip in the animation (since ship_create() can take a long time if
3039         // the ship model is not in memory
3040         if ( Commit_pressed ) {
3041                 if(Game_mode & GM_MULTIPLAYER){
3042                         multi_ts_commit_pressed();                      
3043                 } else {
3044                         commit_pressed();
3045                 }               
3046                 Commit_pressed = 0;
3047         }
3048 }
3049
3050 // -------------------------------------------------------------------------------
3051 // weapon_select_close() will free the bitmap slot and memory that was allocated
3052 // to store the mask bitmap.
3053 //
3054 // Weapon_select_open is cleared when this function completes.
3055 //
3056 void weapon_select_close()
3057 {
3058         if ( !Weapon_select_open ) {
3059                 nprintf(("Alan","weapon_select_close() returning without doing anything\n"));
3060                 return;
3061         }
3062
3063         nprintf(("Alan", "Entering weapon_select_close()\n"));
3064
3065         stop_weapon_animation();
3066
3067         // done with the bitmaps, so unlock it
3068         bm_unlock(WeaponSelectMaskBitmap);
3069
3070         Weapon_ui_window.destroy();
3071
3072 #ifdef MAKE_FS1
3073         common_free_interface_palette();
3074 #endif
3075
3076         // unload bitmaps
3077         help_overlay_unload(WL_OVERLAY);
3078
3079         bm_unload(WeaponSelectMaskBitmap);
3080
3081         wl_unload_icons();
3082         wl_unload_all_anim_instances();
3083         wl_unload_all_anims();
3084
3085         Selected_wl_class = -1;
3086         Weapon_select_open = 0;
3087 }
3088
3089
3090 // ------------------------------------------------------------------------
3091 //      wl_render_icon_count()
3092 //              renders the number next to the weapon icon
3093 //
3094 // input:       x,y                     =>              x,y screen position OF THE ICON (NOT where u want the text, 
3095 //                                                                              this is calculated to prevent overlapping)
3096 //                              num                     =>              the actual count to be printed
3097 //
3098 void wl_render_icon_count(int num, int x, int y)
3099 {
3100         char buf[32];
3101         int num_w, num_h;
3102         int number_to_draw = (num > 1000) ? 999 : num;          // cap count @ 999
3103         SDL_assert(number_to_draw >= 0);
3104
3105         SDL_snprintf(buf, SDL_arraysize(buf), "%d", number_to_draw);
3106         gr_get_string_size(&num_w, &num_h, buf, strlen(buf));
3107
3108         // render
3109         gr_set_color_fast(&Color_white);
3110 #ifdef MAKE_FS1
3111         // strict left align
3112         gr_string(x-21, y+8, buf);
3113 #else
3114         gr_string(x-num_w-4, y+8, buf);
3115 #endif
3116 }
3117
3118
3119 // ------------------------------------------------------------------------
3120 //      wl_render_icon()
3121 //
3122 // input:       index                   =>              index into Wl_icons[], identifying which weapon to draw
3123 //                              x,y                     =>              x,y screen position to draw icon at
3124 //                              num                     =>              count for weapon
3125 //                              draw_num_flag =>        0 if not to draw count for weapon, nonzero otherwise
3126 //                              hot_mask                =>              value that should match Hot_weapon_icon to show mouse is over
3127 //                              hot_bank_mask =>        value that should match Hot_weapon_bank_icon to show mouse is over
3128 //                              select_mask     =>              value that should match Selected_wl_class to show icon is selected
3129 //
3130 void wl_render_icon(int index, int x, int y, int num, int draw_num_flag, int hot_mask, int hot_bank_mask, int select_mask)
3131 {
3132         int                             bitmap_id;
3133         wl_icon_info    *icon;
3134
3135         if ( Selected_wl_slot == -1 )
3136                 return;
3137
3138         icon = &Wl_icons[index];
3139
3140         if ( icon->icon_bmaps[0] == -1 ) {
3141                 wl_load_icons(index);
3142         }
3143                 
3144         // assume default bitmap is to be used
3145         bitmap_id = icon->icon_bmaps[WEAPON_ICON_FRAME_NORMAL]; // normal frame
3146
3147         if ( bitmap_id < 0 ) {
3148                 Int3();
3149                 return;
3150         }
3151
3152         // next check if ship has mouse over it
3153         if ( !wl_icon_being_carried() ) {
3154                 if ( Hot_weapon_icon > -1 && Hot_weapon_icon == hot_mask )
3155                         bitmap_id = icon->icon_bmaps[WEAPON_ICON_FRAME_HOT];
3156
3157                 if ( Hot_weapon_bank_icon > -1 && Hot_weapon_bank_icon == hot_bank_mask )
3158                         bitmap_id = icon->icon_bmaps[WEAPON_ICON_FRAME_HOT];
3159         }
3160
3161         // if icon is selected
3162         if ( Selected_wl_class > -1 ) {
3163                 if ( Selected_wl_class == select_mask)
3164                         bitmap_id = icon->icon_bmaps[WEAPON_ICON_FRAME_SELECTED];       // selected icon
3165         }
3166
3167         // if icon is disabled
3168         if ( !icon->can_use ) {
3169                 bitmap_id = icon->icon_bmaps[WEAPON_ICON_FRAME_DISABLED];       // disabled icon
3170         }
3171
3172         gr_set_color_fast(&Color_blue);
3173         gr_set_bitmap(bitmap_id, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3174         gr_bitmap(x, y);
3175
3176         // draw the number of the item
3177         // now, right justified
3178         if ( draw_num_flag != 0 ) {             
3179 #ifdef MAKE_FS1
3180                 // add a little extra text padding for secondary weapons
3181                 if ( hot_mask > 3 ) {
3182                         wl_render_icon_count(num, x-9, y);
3183                 } else {
3184                         wl_render_icon_count(num, x, y);
3185                 }
3186 #else
3187                 wl_render_icon_count(num, x, y);
3188 #endif
3189         }
3190 }
3191
3192 // ------------------------------------------------------------------------
3193 //      wl_draw_ship_weapons()
3194 //
3195 // Draw the icons for the weapons that are currently on the selected ship
3196 //
3197 // input:       slot_num                =>              Slot to draw weapons for
3198 //
3199 void wl_draw_ship_weapons(int index)
3200 {
3201         int             i;
3202         int             *wep, *wep_count;
3203
3204         if ( index == -1 )
3205                 return;
3206
3207         SDL_assert(index >= 0 && index < MAX_WSS_SLOTS);
3208         wep = Wss_slots[index].wep;
3209         wep_count = Wss_slots[index].wep_count;
3210
3211         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3212
3213                 if ( Carried_wl_icon.from_bank == i && Carried_wl_icon.from_slot == index ) {
3214                         continue;
3215                 }
3216
3217                 if ( (wep[i] != -1) && (wep_count[i] > 0) ) {
3218                         int x_offset = 0;
3219                         //x_offset = wl_fury_missile_offset_hack(wep[i], wep_count[i]);
3220                         wl_render_icon( wep[i], Wl_bank_coords[gr_screen.res][i][0]+x_offset, Wl_bank_coords[gr_screen.res][i][1], wep_count[i], Wl_bank_count_draw_flags[i], -1, i, wep[i]);
3221                 }
3222         }
3223 }
3224
3225 // ------------------------------------------------------------------------
3226 //      draw_wl_icon_with_number()
3227 //
3228 // input:       list_count                      =>              list position on screen (0-7)
3229 //                              weapon_class            =>              class of weapon
3230 //
3231 void draw_wl_icon_with_number(int list_count, int weapon_class)
3232 {
3233         SDL_assert( list_count >= 0 && list_count < 8 );        
3234
3235         wl_render_icon(weapon_class, Wl_weapon_icon_coords[gr_screen.res][list_count][0], Wl_weapon_icon_coords[gr_screen.res][list_count][1],
3236                                            Wl_pool[weapon_class], 1, list_count, -1, weapon_class);
3237 }
3238
3239 // ------------------------------------------------------------------------
3240 //      draw_wl_icons()
3241 //
3242 // Draw the weapon icons that are available
3243 void draw_wl_icons()
3244 {
3245         int i, count;
3246
3247         count=0;
3248         for ( i = Plist_start; i < Plist_size; i++ ) {
3249                 draw_wl_icon_with_number(count, Plist[i]);
3250                 if ( ++count > 3 )
3251                         break;
3252         }
3253
3254         count=0;
3255         for ( i = Slist_start; i < Slist_size; i++ ) {
3256                 draw_wl_icon_with_number(count+4, Slist[i]);
3257                 if ( ++count > 3 )
3258                         break;
3259         }
3260 }
3261
3262 // ------------------------------------------------------------------------
3263 // wl_pick_icon_from_list()
3264 //
3265 // determine if an icon from the scrollable weapon list can be picked up 
3266 // (for drag and drop).  It calculates the difference in x & y between the icon
3267 // and the mouse, so we can move the icon with the mouse in a realistic way
3268 // input: index (0..7) 
3269 void wl_pick_icon_from_list(int index)
3270 {
3271         int weapon_class, mx, my;
3272
3273         // if this is a multiplayer game and the player is an observer, he can never pick any weapons up
3274         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3275                 return;
3276         }
3277
3278         // if a weapon is being carried, do nothing
3279         if ( wl_icon_being_carried() ) {
3280                 return;
3281         }
3282
3283         if ( index < 4 ) {
3284                 weapon_class = Plist[Plist_start+index];
3285         } else {
3286                 weapon_class = Slist[Slist_start+index-4];
3287         }
3288
3289         // there isn't a weapon there at all!
3290         if ( weapon_class < 0 ) 
3291                 return;
3292
3293         // no weapons left of that class
3294         if ( Wl_pool[weapon_class] <= 0 ) {
3295                 return;
3296         }
3297
3298 /*
3299         // some are available, but weapon cannot be used on current ship class
3300         if ( !Wl_icons[weapon_class].can_use ) {
3301                 wl_pause_anim();
3302
3303                 int ship_class = Wss_slots[Selected_wl_slot].ship_class;
3304                 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "A %s is unable to carry %s weaponry", Ship_info[ship_class].name, Weapon_info[weapon_class].name);
3305
3306                 wl_unpause_anim();
3307                 return;
3308         }
3309 */
3310
3311         wl_set_carried_icon(-1, -1, weapon_class);
3312         common_flash_button_init();
3313
3314         mouse_get_pos( &mx, &my );
3315         Wl_delta_x = Wl_weapon_icon_coords[gr_screen.res][index][0] - mx;
3316         Wl_delta_y = Wl_weapon_icon_coords[gr_screen.res][index][1] - my;
3317 }
3318
3319 // ------------------------------------------------------------------------
3320 //      pick_from_ship_slot()
3321 //
3322 // input: num   ->      index into shipb banks (0..2 primary, 3..6 secondary)
3323 void pick_from_ship_slot(int num)
3324 {
3325         int mx, my, *wep, *wep_count;
3326                 
3327         SDL_assert(num < 7);
3328
3329         if ( Selected_wl_slot == -1 )
3330                 return;
3331
3332         if ( wl_icon_being_carried() )
3333                 return;
3334
3335         if ( ss_disabled_slot( Selected_wl_slot ) )
3336                 return;
3337
3338         wep = Wss_slots[Selected_wl_slot].wep;
3339         wep_count = Wss_slots[Selected_wl_slot].wep_count;
3340
3341         // check if a weapon even exists in that slot
3342         if ( (wep[num] < 0) || (wep_count[num] <= 0) ) {
3343                 return;
3344         }
3345
3346         SDL_assert(Wl_icons[wep[num]].can_use);
3347
3348         wl_set_carried_icon(num, Selected_wl_slot, wep[num]);
3349         common_flash_button_init();
3350                         
3351         mouse_get_pos( &mx, &my );
3352
3353         int x_offset = wl_fury_missile_offset_hack(wep[num], wep_count[num]);
3354         Wl_delta_x = Wl_bank_coords[gr_screen.res][num][0] - mx + x_offset;
3355         Wl_delta_y = Wl_bank_coords[gr_screen.res][num][1] - my;
3356
3357         Carried_wl_icon.from_x = mx;
3358         Carried_wl_icon.from_y = my;
3359 }
3360
3361 // determine if this slot has no weapons
3362 int wl_slots_all_empty(wss_unit *slot)
3363 {
3364         int                     i;
3365
3366         for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3367                 if ( (slot->wep_count[i] > 0) && (slot->wep[i] >= 0) ) 
3368                         return 0;
3369         }
3370
3371         return 1;
3372 }
3373
3374 // ------------------------------------------------------------------------
3375 //      wl_update_ship_weapons()
3376 //
3377 // Change a ship's weapons based on the information contained in the
3378 // Weapon_data[] structure that is filled in during weapon loadout
3379 //
3380 // returns: -1  =>      if the playre ship has no weapons
3381 //                              0       =>      function finished without errors        
3382 int wl_update_ship_weapons(int objnum, wss_unit *slot )
3383 {
3384         // AL 11-15-97: Ensure that the player ship hasn't removed all 
3385         //                                       weapons from their ship.  This will cause a warning to appear.
3386         if ( objnum == OBJ_INDEX(Player_obj) && Weapon_select_open ) {
3387                 if ( wl_slots_all_empty(slot) ) {
3388                         return -1;
3389                 }
3390         }
3391
3392         wl_bash_ship_weapons(&Ships[Objects[objnum].instance].weapons, slot);
3393         return 0;
3394 }
3395
3396
3397 // ------------------------------------------------------------------------
3398 //      wl_update_parse_object_weapons()
3399 //
3400 // Set the Pilot subsystem of a parse_object to the weapons that are setup
3401 // for the wing_block,wing_slot ship
3402 //
3403 // input:       pobjp   =>      pointer to parse object that references Pilot subsystem
3404 //
3405 void wl_update_parse_object_weapons(p_object *pobjp, wss_unit *slot)
3406 {
3407         int                             i,      j, sidx, pilot_index, max_count;
3408         subsys_status   *ss;
3409
3410         SDL_assert(slot->ship_class >= 0);
3411
3412         pilot_index = wl_get_pilot_subsys_index(pobjp);
3413
3414         if ( pilot_index == -1 ) 
3415                 return;
3416                                                 
3417         ss = &Subsys_status[pilot_index];
3418
3419         for ( i = 0; i < MAX_PRIMARY_BANKS; i++ ) {
3420                 ss->primary_banks[i] = -1;              
3421         }
3422
3423         for ( i = 0; i < MAX_SECONDARY_BANKS; i++ ) {
3424                 ss->secondary_banks[i] = -1;            
3425         }
3426
3427         j = 0;
3428         for ( i = 0; i < MAX_WL_PRIMARY; i++ ) {
3429                 if ( (slot->wep_count[i] > 0) && (slot->wep[i] >= 0) ) {
3430                         ss->primary_banks[j] = slot->wep[i];
3431                         j++;
3432                 }
3433         }
3434
3435         j = 0;
3436         for ( i = 0; i < MAX_WL_SECONDARY; i++ ) {
3437                 sidx = i+MAX_WL_PRIMARY;
3438                 if ( (slot->wep_count[sidx] > 0) && (slot->wep[sidx] >= 0) ) {
3439                         ss->secondary_banks[j] = slot->wep[sidx];
3440                         // Important: the secondary_ammo[] value is a percentage of max capacity!
3441                         max_count = wl_calc_missile_fit(slot->wep[sidx], Ship_info[slot->ship_class].secondary_bank_ammo_capacity[j]);
3442                         ss->secondary_ammo[j] = fl2i( i2fl(slot->wep_count[sidx]) / max_count * 100.0f + 0.5f);
3443                         j++;
3444                 }
3445         }
3446 }
3447
3448 // ------------------------------------------------------------------------
3449 // stop_weapon_animation()
3450 //
3451 // Stop the current weapon animation from playing.
3452 //
3453 void stop_weapon_animation()
3454 {
3455         if ( Weapon_anim_class < 0 )
3456                 return;
3457
3458         if ( anim_playing(Wl_icons[Weapon_anim_class].anim_instance) )
3459                 anim_release_render_instance(Wl_icons[Weapon_anim_class].anim_instance);
3460
3461         Wl_icons[Weapon_anim_class].anim_instance = NULL;
3462         Weapon_anim_class = -1;
3463 }
3464
3465 // ------------------------------------------------------------------------
3466 // start_weapon_animation()
3467 //
3468 // Start the current weapon animation from playing.
3469 //
3470 void start_weapon_animation(int weapon_class) 
3471 {
3472         wl_icon_info    *icon;
3473         int *weapon_ani_coords;
3474
3475         if ( weapon_class < 0 )
3476                 return;
3477
3478         if ( weapon_class == Weapon_anim_class ) 
3479                 return;
3480
3481         // get the correct weapon animations coords
3482         if (Game_mode & GM_MULTIPLAYER) {
3483                 weapon_ani_coords = Wl_weapon_ani_coords_multi[gr_screen.res];
3484         } else {
3485                 weapon_ani_coords = Wl_weapon_ani_coords[gr_screen.res];
3486         }
3487
3488         icon = &Wl_icons[weapon_class];
3489
3490         // stop current animation playing
3491         stop_weapon_animation();
3492
3493         // see if we need to load in the animation from disk
3494         if ( icon->anim == NULL ) {
3495                 wl_load_anim(weapon_class);
3496                 /*
3497                 icon->anim = anim_load(Weapon_info[weapon_class].anim_filename, 1);
3498                 if ( icon->anim == NULL ) {
3499                         Int3(); // could not open the weapon animation
3500                         return;
3501                 }
3502                 */
3503         }
3504
3505         // see if we need to get an instance
3506         if ( icon->anim_instance == NULL ) {
3507                 anim_play_struct aps;
3508
3509                 anim_play_init(&aps, icon->anim, weapon_ani_coords[0], weapon_ani_coords[1]);
3510                 aps.screen_id = ON_WEAPON_SELECT;
3511                 aps.framerate_independent = 1;
3512                 aps.skip_frames = 0;
3513                 icon->anim_instance = anim_play(&aps);
3514                 gamesnd_play_iface(SND_WEAPON_ANIM_START);
3515         }
3516
3517         Weapon_anim_class = weapon_class;
3518
3519         // start the text wipe
3520         wl_weapon_desc_start_wipe();
3521 }
3522
3523 // reset the weapons loadout to the defaults in the mission
3524 void wl_reset_to_defaults()
3525 {
3526         // don't reset of weapons pool in multiplayer
3527         if(Game_mode & GM_MULTIPLAYER){
3528                 return;
3529         }
3530
3531         wl_init_pool(&Team_data[Common_team]);
3532         wl_init_icon_lists();
3533         wl_fill_slots();
3534         wl_reset_selected_slot();
3535         wl_reset_carried_icon();
3536         wl_maybe_reset_selected_weapon_class();
3537 }
3538
3539 // Bash ship weapons, based on what is stored in the stored weapons loadout
3540 // NOTE: Wss_slots[] is assumed to be correctly set
3541 void wl_bash_ship_weapons(ship_weapon *swp, wss_unit *slot)
3542 {
3543         int             i, j, sidx;
3544         
3545         for ( i = 0; i < MAX_PRIMARY_BANKS; i++ ) {
3546                 swp->primary_bank_weapons[i] = -1;              
3547         }
3548
3549         for ( i = 0; i < MAX_SECONDARY_BANKS; i++ ) {
3550                 swp->secondary_bank_weapons[i] = -1;            
3551         }
3552
3553         j = 0;
3554         for ( i = 0; i < MAX_WL_PRIMARY; i++ ) {
3555                 if ( (slot->wep_count[i] > 0) && (slot->wep[i] >= 0) ) {
3556                         swp->primary_bank_weapons[j] = slot->wep[i];                    
3557                         j++;
3558                 }
3559         }
3560         swp->num_primary_banks = j;
3561
3562         j = 0;
3563         for ( i = 0; i < MAX_WL_SECONDARY; i++ ) {
3564                 sidx = i+MAX_WL_PRIMARY;
3565                 if ( (slot->wep_count[sidx] > 0) && (slot->wep[sidx] >= 0) ) {
3566                         swp->secondary_bank_weapons[j] = slot->wep[sidx];
3567                         swp->secondary_bank_ammo[j] = slot->wep_count[sidx];
3568                         j++;
3569                 }
3570         }
3571         swp->num_secondary_banks = j;
3572 }
3573
3574 // utility function for swapping two banks
3575 void wl_swap_weapons(int ship_slot, int from_bank, int to_bank)
3576 {
3577         wss_unit        *slot;
3578         int     tmp;
3579         slot = &Wss_slots[ship_slot];
3580
3581         if ( from_bank == to_bank ) {
3582                 return;
3583         }
3584
3585         // swap weapon type
3586         tmp = slot->wep[from_bank];
3587         slot->wep[from_bank] = slot->wep[to_bank];
3588         slot->wep[to_bank] = tmp;
3589
3590         // swap weapon count
3591         tmp = slot->wep_count[from_bank];
3592         slot->wep_count[from_bank] = slot->wep_count[to_bank];
3593         slot->wep_count[to_bank] = tmp;
3594 }
3595
3596 // utility function used to put back overflow into the weapons pool
3597 void wl_saturate_bank(int ship_slot, int bank)
3598 {
3599         wss_unit        *slot;
3600         int             max_count, overflow;
3601
3602         slot = &Wss_slots[ship_slot];
3603
3604         if ( (slot->wep[bank] < 0) || (slot->wep_count <= 0) ) {
3605                 return;
3606         }
3607
3608         max_count = wl_calc_missile_fit(slot->wep[bank], Ship_info[slot->ship_class].secondary_bank_ammo_capacity[bank-3]);
3609         overflow = slot->wep_count[bank] - max_count;
3610         if ( overflow > 0 ) {
3611                 slot->wep_count[bank] -= overflow;
3612                 // add overflow back to pool
3613                 Wl_pool[slot->wep[bank]] += overflow;
3614         }
3615 }
3616
3617 // exit: 0 -> no data changed
3618 //                      1 -> data changed
3619 //       sound => gets filled with sound id to play
3620 int wl_swap_slot_slot(int from_bank, int to_bank, int ship_slot, int *sound)
3621 {
3622         wss_unit        *slot;
3623         slot = &Wss_slots[ship_slot];
3624
3625         if ( slot->ship_class == -1 ) {
3626                 Int3(); // should not be possible
3627                 return 0;
3628         }
3629         
3630         // do nothing if swapping with self
3631         if ( from_bank == to_bank ) {
3632                 *sound=SND_ICON_DROP_ON_WING;
3633                 return 0;       // no update
3634         }
3635
3636         // ensure that source bank exists and has something to pick from
3637         if ( slot->wep[from_bank] == -1 || slot->wep_count[from_bank] <= 0 ) {
3638                 return 0;
3639         }
3640
3641         // ensure that the dest bank exists
3642         if ( slot->wep_count[to_bank] < 0 ) {
3643                 return 0;
3644         }
3645
3646         // ensure that the banks are both of the same class
3647         if ( (IS_BANK_PRIMARY(from_bank) && IS_BANK_SECONDARY(to_bank)) || (IS_BANK_SECONDARY(from_bank) && IS_BANK_PRIMARY(to_bank)) ) {
3648                 // put from_bank back into list
3649                 Wl_pool[slot->wep[from_bank]] += slot->wep_count[from_bank];;           // return to list
3650                 slot->wep[from_bank] = -1;                                                                                                              // remove from slot
3651                 slot->wep_count[from_bank] = 0;
3652                 *sound=SND_ICON_DROP;
3653                 return 1;
3654         }
3655
3656         // case 1: primaries (easy)
3657         if ( IS_BANK_PRIMARY(from_bank) && IS_BANK_PRIMARY(to_bank) ) {
3658                 wl_swap_weapons(ship_slot, from_bank, to_bank);
3659                 *sound=SND_ICON_DROP_ON_WING;
3660                 return 1;
3661         }
3662
3663         // case 2: secondaries (harder)
3664         if ( IS_BANK_SECONDARY(from_bank) && IS_BANK_SECONDARY(to_bank) ) {
3665
3666                 // case 2a: secondaries are the same type
3667                 if ( slot->wep[from_bank] == slot->wep[to_bank] ) {
3668                         int dest_max, dest_can_fit, source_can_give;
3669                         dest_max = wl_calc_missile_fit(slot->wep[to_bank], Ship_info[slot->ship_class].secondary_bank_ammo_capacity[to_bank-3]);
3670
3671                         dest_can_fit = dest_max - slot->wep_count[to_bank];
3672
3673                         if ( dest_can_fit <= 0 ) {
3674                                 // dest bank is already full.. nothing to do here
3675                                 return 0;
3676                         }
3677
3678                         // see how much source can give
3679                         source_can_give = min(dest_can_fit, slot->wep_count[from_bank]);
3680
3681                         if ( source_can_give > 0 ) {                    
3682                                 slot->wep_count[to_bank] += source_can_give;            // add to dest
3683                                 slot->wep_count[from_bank] -= source_can_give;  // take from source
3684                                 *sound=SND_ICON_DROP_ON_WING;
3685                                 return 1;
3686                         } else {
3687                                 return 0;
3688                         }
3689                 }
3690
3691                 // case 2b: secondaries are different types
3692                 if ( slot->wep[from_bank] != slot->wep[to_bank] ) {
3693
3694                         // swap 'em 
3695                         wl_swap_weapons(ship_slot, from_bank, to_bank);
3696
3697                         // put back some on list if required
3698                         wl_saturate_bank(ship_slot, from_bank);
3699                         wl_saturate_bank(ship_slot, to_bank);
3700                         *sound=SND_ICON_DROP_ON_WING;
3701                         return 1;
3702                 }
3703         }
3704
3705         Int3();         // should never get here
3706         return 0;
3707 }
3708
3709 // exit: 0 -> no data changed
3710 //                      1 -> data changed
3711 //       sound => gets filled with sound id to play
3712 int wl_dump_to_list(int from_bank, int to_list, int ship_slot, int *sound)
3713 {
3714         wss_unit        *slot;
3715         slot = &Wss_slots[ship_slot];
3716
3717         // ensure that source bank exists and has something to pick from
3718         if ( slot->wep[from_bank] == -1 || slot->wep_count[from_bank] <= 0 ) {
3719                 return 0;
3720         }
3721
3722         // put weapon bank to the list
3723         Wl_pool[to_list] += slot->wep_count[from_bank];                 // return to list
3724         slot->wep[from_bank] = -1;                                                                              // remove from slot
3725         slot->wep_count[from_bank] = 0;
3726         *sound=SND_ICON_DROP;
3727
3728         return 1;
3729 }
3730
3731 // exit: 0 -> no data changed
3732 //                      1 -> data changed
3733 //       sound => gets filled with sound id to play
3734 int wl_grab_from_list(int from_list, int to_bank, int ship_slot, int *sound)
3735 {
3736         wss_unit        *slot;
3737         slot = &Wss_slots[ship_slot];
3738         int max_fit;
3739
3740         // ensure that the banks are both of the same class
3741         if ( (IS_LIST_PRIMARY(from_list) && IS_BANK_SECONDARY(to_bank)) || (IS_LIST_SECONDARY(from_list) && IS_BANK_PRIMARY(to_bank)) ) {
3742                 // do nothing
3743                 *sound=SND_ICON_DROP;
3744                 return 0;
3745         }
3746
3747         // ensure that dest bank exists
3748         if ( slot->wep_count[to_bank] < 0 ) {
3749                 *sound=SND_ICON_DROP;
3750                 return 0;
3751         }
3752
3753         // bank should be empty:
3754         SDL_assert(slot->wep_count[to_bank] == 0);
3755         SDL_assert(slot->wep[to_bank] < 0);
3756
3757         // ensure that pool has weapon
3758         if ( Wl_pool[from_list] <= 0 ) {
3759                 return 0;
3760         }
3761
3762         // find how much dest bank can fit
3763         if ( to_bank < MAX_WL_PRIMARY ) {
3764                 max_fit = 1;
3765         } else {
3766                 max_fit = wl_calc_missile_fit(from_list, Ship_info[slot->ship_class].secondary_bank_ammo_capacity[to_bank-MAX_WL_PRIMARY]);
3767         }
3768
3769         // take weapon from list
3770         if ( Wl_pool[from_list] < max_fit ) {
3771                 max_fit = Wl_pool[from_list];
3772         }
3773         Wl_pool[from_list] -= max_fit;
3774
3775         // put on the slot
3776         slot->wep[to_bank] = from_list;
3777         slot->wep_count[to_bank] = max_fit;
3778
3779         *sound=SND_ICON_DROP_ON_WING;
3780         return 1;
3781 }
3782
3783 // exit: 0 -> no data changed
3784 //                      1 -> data changed
3785 //       sound => gets filled with sound id to play
3786 int wl_swap_list_slot(int from_list, int to_bank, int ship_slot, int *sound)
3787 {
3788         wss_unit        *slot;
3789         slot = &Wss_slots[ship_slot];
3790         int max_fit;
3791
3792         // ensure that the banks are both of the same class
3793         if ( (IS_LIST_PRIMARY(from_list) && IS_BANK_SECONDARY(to_bank)) || (IS_LIST_SECONDARY(from_list) && IS_BANK_PRIMARY(to_bank)) ) {
3794                 // do nothing
3795                 *sound=SND_ICON_DROP;
3796                 return 0;
3797         }
3798
3799         // ensure that dest bank exists
3800         if ( slot->wep_count[to_bank] < 0 ) {
3801                 return 0;
3802         }
3803
3804         // bank should have something in it
3805         SDL_assert(slot->wep_count[to_bank] > 0);
3806         SDL_assert(slot->wep[to_bank] >= 0);
3807
3808         // ensure that pool has weapon
3809         if ( Wl_pool[from_list] <= 0 ) {
3810                 return 0;
3811         }
3812
3813         // dump slot weapon back into list
3814         Wl_pool[slot->wep[to_bank]] += slot->wep_count[to_bank];
3815         slot->wep_count[to_bank] = 0;
3816         slot->wep[to_bank] = -1;
3817
3818         // put weapon on ship from list
3819         
3820         // find how much dest bank can fit
3821         if ( to_bank < MAX_WL_PRIMARY ) {
3822                 max_fit = 1;
3823         } else {
3824                 max_fit = wl_calc_missile_fit(from_list, Ship_info[slot->ship_class].secondary_bank_ammo_capacity[to_bank-MAX_WL_PRIMARY]);
3825         }
3826
3827         // take weapon from list
3828         if ( Wl_pool[from_list] < max_fit ) {
3829                 max_fit = Wl_pool[from_list];
3830         }
3831         Wl_pool[from_list] -= max_fit;
3832
3833         // put on the slot
3834         slot->wep[to_bank] = from_list;
3835         slot->wep_count[to_bank] = max_fit;
3836
3837         *sound=SND_ICON_DROP_ON_WING;
3838         return 1;
3839 }
3840
3841 // update any interface data that may be dependent on Wss_slots[] 
3842 void wl_synch_interface()
3843 {
3844 }
3845
3846 void wl_apply(int mode,int from_bank,int from_list,int to_bank,int to_list,int ship_slot,int player_index)
3847 {
3848         int update=0;
3849         int sound=-1;
3850         net_player *pl;
3851
3852         // get the appropriate net player
3853         if(Game_mode & GM_MULTIPLAYER){
3854                 if(player_index == -1){
3855                         pl = Net_player;
3856                 } else {
3857                         pl = &Net_players[player_index];
3858                 }
3859         } else {
3860                 pl = NULL;
3861         }
3862
3863         switch(mode){
3864         case WSS_SWAP_SLOT_SLOT:
3865                 update = wl_swap_slot_slot(from_bank, to_bank, ship_slot, &sound);
3866                 break;
3867         case WSS_DUMP_TO_LIST:
3868                 update = wl_dump_to_list(from_bank, to_list, ship_slot, &sound);
3869                 break;
3870         case WSS_GRAB_FROM_LIST:
3871                 update = wl_grab_from_list(from_list, to_bank, ship_slot, &sound);
3872                 break;
3873         case WSS_SWAP_LIST_SLOT:
3874                 update = wl_swap_list_slot(from_list, to_bank, ship_slot, &sound);
3875                 break;
3876         }
3877
3878         // only play this sound if the move was done locally (by the host in other words)
3879         if ( (sound >= 0) && (player_index == -1) ) {   
3880                 gamesnd_play_iface(sound);      
3881         }       
3882
3883         if ( update ) {
3884                 if ( MULTIPLAYER_HOST ) {
3885                         int size;
3886                         ubyte wss_data[MAX_PACKET_SIZE-20];
3887
3888                         size = store_wss_data(wss_data, MAX_PACKET_SIZE-20,sound,player_index);                 
3889                         SDL_assert(pl != NULL);
3890                         send_wss_update_packet(pl->p_info.team,wss_data, size);
3891                 }
3892
3893                 if(Game_mode & GM_MULTIPLAYER){
3894                         SDL_assert(pl != NULL);
3895
3896                         // if the pool we're using has changed, synch stuff up
3897                         if(pl->p_info.team == Net_player->p_info.team){
3898                                 wl_synch_interface();                   
3899                         }
3900                 } else {
3901                         wl_synch_interface();
3902                 }
3903         }               
3904 }
3905
3906 void wl_drop(int from_bank,int from_list,int to_bank,int to_list, int ship_slot, int player_index)
3907 {
3908         int mode;
3909         net_player *pl;
3910
3911         // get the appropriate net player
3912         if(Game_mode & GM_MULTIPLAYER){
3913                 if(player_index == -1){
3914                         pl = Net_player;
3915                 } else {
3916                         pl = &Net_players[player_index];
3917                 }
3918         } else {
3919                 pl = NULL;
3920         }
3921
3922         common_flash_button_init();
3923         if ( !(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_HOST ) {
3924                 if ( (Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) ) {
3925                         SDL_assert(pl != NULL);
3926                         // set the global pointers to the right pools
3927                         ss_set_team_pointers(pl->p_info.team);
3928                 }
3929
3930
3931                 mode = wss_get_mode(from_bank, from_list, to_bank, to_list, ship_slot);
3932                 if ( mode >= 0 ) {
3933                         wl_apply(mode, from_bank, from_list, to_bank, to_list, ship_slot, player_index);
3934                 }               
3935
3936                 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3937                         // set the global pointers to the right pools
3938                         ss_set_team_pointers(Net_player->p_info.team);
3939                 }
3940         } else {
3941                 send_wss_request_packet(Net_player->player_id, from_bank, from_list, to_bank, to_list, ship_slot, -1, WSS_WEAPON_SELECT);
3942         }
3943 }
3944