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