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