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