2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/MissionUI/MissionShipChoice.cpp $
15 * C module to allow player ship selection for the mission
18 * Revision 1.2 2002/06/09 04:41:23 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:10 root
25 * 26 11/02/99 3:23p Jefff
26 * "x Meters" to "x Meter" in German
28 * 25 8/05/99 3:40p Jefff
29 * hi-res text adjustments
31 * 24 8/04/99 11:56a Jefff
32 * fixed gamma wing hi-res coordinate error. fixed
33 * ss_load_individual_animation to load anis from a packfile.
35 * 23 7/30/99 4:22p Andsager
36 * restored ship and weapon anim sounds for demo. Added sound for
37 * changing ship in weapon loadout screen.
39 * 22 7/28/99 12:23p Jefff
40 * updated hi-res wing icon coords
42 * 21 7/21/99 3:24p Andsager
43 * Modify demo to use 2 frame ship and weapon select anis and cut sounds
46 * 20 7/16/99 2:23p Anoop
49 * 19 7/16/99 1:49p Dave
50 * 8 bit aabitmaps. yay.
52 * 18 7/15/99 6:36p Jamesa
53 * Moved default ship name into the ships.tbl
55 * 17 7/15/99 9:20a Andsager
56 * FS2_DEMO initial checkin
58 * 16 6/29/99 7:39p Dave
59 * Lots of small bug fixes.
61 * 15 6/04/99 11:32a Dave
62 * Added reset text to ship select screen. Fixed minor xstr bug in ui
65 * 14 3/23/99 9:26p Neilk
66 * fixed various multiplayer lock button problems
68 * 13 3/23/99 11:55a Neilk
69 * new support for ship anis
71 * 14 3/15/99 6:27p Neilk
72 * Added hires support for the ship animations
74 * 13 3/15/99 11:18a Neilk
75 * Modified animation code so ship animations loop back to frame 51
77 * 12 3/12/99 12:02p Davidg
78 * Modified coordinates for low res ship animations for new artwork
80 * 11 3/10/99 6:21p Neilk
81 * Added new artwork for hires
83 * 10 2/21/99 6:01p Dave
84 * Fixed standalone WSS packets.
86 * 9 2/18/99 11:46a Neilk
87 * hires interface coord support
89 * 8 2/11/99 3:08p Dave
90 * PXO refresh button. Very preliminary squad war support.
92 * 7 2/01/99 5:55p Dave
93 * Removed the idea of explicit bitmaps for buttons. Fixed text
94 * highlighting for disabled gadgets.
96 * 6 1/29/99 4:17p Dave
97 * New interface screens.
99 * 5 12/18/98 1:13a Dave
100 * Rough 1024x768 support for Direct3D. Proper detection and usage through
103 * 4 11/30/98 1:07p Dave
104 * 16 bit conversion, first run.
106 * 3 10/13/98 9:28a Dave
107 * Started neatening up freespace.h. Many variables renamed and
108 * reorganized. Added AlphaColors.[h,cpp]
110 * 2 10/07/98 10:53a Dave
113 * 1 10/07/98 10:50a Dave
115 * 102 9/11/98 4:14p Dave
116 * Fixed file checksumming of < file_size. Put in more verbose kicking and
117 * PXO stats store reporting.
119 * 101 6/09/98 10:31a Hoffoss
120 * Created index numbers for all xstr() references. Any new xstr() stuff
121 * added from here on out should be added to the end if the list. The
122 * current list count can be found in FreeSpace.cpp (search for
125 * 100 6/01/98 11:43a John
126 * JAS & MK: Classified all strings for localization.
128 * 99 5/23/98 5:50p Lawrance
129 * Don't reset scroll offset when rebuilding the list
131 * 98 5/06/98 11:50p Lawrance
132 * Clean up help overlay code for loadout screens
134 * 97 4/30/98 6:03p Lawrance
135 * Make drag and drop work better.
137 * 96 4/29/98 3:31p Lawrance
138 * draw disabled frames for icons when appropriate
140 * 95 4/28/98 9:35a Dave
141 * Remove bogus assert in create_wings() for ships which arrive late and
142 * haven't been created yet.
144 * 94 4/27/98 6:02p Dave
145 * Modify how missile scoring works. Fixed a team select ui bug. Speed up
146 * multi_lag system. Put in new main hall.
148 * 93 4/14/98 12:57a Dave
149 * Made weapon select screen show netplayer names above ships. Fixed pilot
150 * info popup to show the status of pilot images more correctly.
152 * 92 4/13/98 3:27p Lawrance
153 * fix coords for ship selection pool numbers
155 * 91 4/13/98 3:11p Andsager
156 * Fixed bug when there is no description for a ship.
158 * 90 4/10/98 4:51p Hoffoss
159 * Made several changes related to tooltips.
161 * 89 4/05/98 7:43p Lawrance
162 * fix up saving/restoring of link status and auto-target/match-speed.
164 * 88 4/03/98 4:16p Adam
165 * changed coord's and skip frame for new SS animations
167 * 87 4/02/98 11:40a Lawrance
168 * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
170 * 86 4/01/98 11:19p Dave
171 * Put in auto-loading of xferred pilot pic files. Grey out background
172 * behind pinfo popup. Put a chatbox message in when players are kicked.
173 * Moved mission title down in briefing. Other ui fixes.
175 * 85 4/01/98 9:21p John
176 * Made NDEBUG, optimized build with no warnings or errors.
178 * 84 3/31/98 11:47p Lawrance
179 * Fix some bugs related to wingmen selection when doing a quick mission
182 * 83 3/31/98 1:50p Duncan
183 * ALAN: fix bugs with selecting alternate weapons
185 * 82 3/30/98 12:18a Lawrance
186 * change some DEMO_RELEASE code to not compile code rather than return
189 * 81 3/29/98 12:55a Lawrance
190 * Get demo build working with limited set of data.
192 * 80 3/26/98 6:01p Dave
193 * Put in file checksumming routine in cfile. Made pilot pic xferring more
194 * robust. Cut header size of voice data packets in half. Put in
195 * restricted game host query system.
197 * 79 3/25/98 8:43p Hoffoss
198 * Changed anim_play() to not be so damn complex when you try and call it.
200 * 78 3/12/98 4:03p Lawrance
201 * don't press buttons when icon dropped on them
203 * 77 3/09/98 11:13a Lawrance
204 * Fix up drop sound effects used in loadout screens.
206 * 76 3/06/98 5:36p Dave
207 * Finished up first rev of team vs team. Probably needs to be debugged
210 * 75 3/05/98 6:48p Lawrance
211 * reposition commit_pressed() to ensure popup gets called after clear but
214 * 74 3/05/98 5:03p Dave
215 * More work on team vs. team support for multiplayer. Need to fix bugs in
218 * 73 3/05/98 12:38a Lawrance
219 * Fix bug with flashing buttons showing over help overlay
221 * 72 3/02/98 5:42p John
222 * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from
223 * afterburner. Made gr_set_clip work good with negative x &y. Made
224 * model_caching be on by default. Made each cached model have it's own
225 * bitmap id. Made asteroids not rotate when model_caching is on.
227 * 71 3/01/98 3:26p Dave
228 * Fixed a few team select bugs. Put in multiplayer intertface sounds.
229 * Corrected how ships are disabled/enabled in team select/weapon select
232 * 70 2/28/98 7:04p Lawrance
233 * Don't show reset button in multiplayer
235 * 69 2/26/98 8:21p Allender
236 * fix compiler warning
238 * 68 2/26/98 4:59p Allender
239 * groundwork for team vs team briefings. Moved weaponry pool into the
240 * Team_data structure. Added team field into the p_info structure.
241 * Allow for mutliple structures in the briefing code.
243 * 67 2/24/98 6:21p Lawrance
244 * Integrate new reset button into loadout screens
246 * 66 2/22/98 4:30p John
247 * More string externalization classification
249 * 65 2/22/98 4:17p John
250 * More string externalization classification... 190 left to go!
252 * 64 2/22/98 12:19p John
253 * Externalized some strings
255 * 63 2/19/98 6:26p Dave
256 * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
257 * initial support for player data uploading.
259 * 62 2/18/98 3:56p Dave
260 * Several bugs fixed for mp team select screen. Put in standalone packet
261 * routing for team select.
263 * 61 2/17/98 6:07p Dave
264 * Tore out old multiplayer team select screen, installed new one.
266 * 60 2/13/98 3:46p Dave
267 * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
270 * 59 2/12/98 2:38p Allender
271 * fix multiplayer primary/secondary weapon problems when ships are
272 * outfitted with less than max number
274 * 58 2/07/98 5:47p Lawrance
275 * reset flashing if a button gets highlighted
277 * 57 2/05/98 11:21p Lawrance
278 * When flashing buttons, use highlight frame
280 * 56 1/30/98 10:00a Allender
281 * made large ships able to attack other ships. Made goal code recognize
282 * when ships removed from wings during ship select
284 * 55 1/22/98 5:26p Dave
285 * Modified some pregame sequencing packets. Starting to repair broken
288 * 54 1/17/98 2:46a Dave
289 * Reworked multiplayer join/accept process. Ingame join still needs to be
292 * 53 1/15/98 4:11p Lawrance
293 * Add call to check if slot is player occupied.
295 * 52 1/13/98 4:47p Allender
296 * change default terran ship to reflect new ship class name
298 * 51 1/12/98 5:17p Dave
299 * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
300 * work through the standalone.
302 * 50 1/10/98 12:46a Lawrance
303 * Store last_modified time for mission into player loadout struct.
305 * 49 1/09/98 6:06p Dave
306 * Put in network sound support for multiplayer ship/weapon select
307 * screens. Made clients exit game correctly through warp effect. Fixed
308 * main hall menu help overlay bug.
310 * 48 1/08/98 11:38a Lawrance
313 * 47 1/08/98 11:36a Lawrance
314 * Get ship select and weapons loadout icon dropping sound effects working
315 * for single and multiplayer
317 * 46 1/02/98 9:10p Lawrance
318 * Big changes to how colors get set on the HUD.
320 * 45 12/29/97 4:21p Lawrance
321 * Flash buttons on briefing/ship select/weapons loadout when enough time
322 * has elapsed without activity.
324 * 44 12/29/97 9:42a Lawrance
325 * Ensure that WING_SLOT_IS_PLAYER gets set correctly in multiplayer.
327 * 43 12/24/97 8:54p Lawrance
328 * Integrating new popup code
330 * 42 12/24/97 1:19p Lawrance
331 * fix some bugs with the multiplayer ship/weapons loadout
333 * 41 12/23/97 5:25p Allender
334 * more fixes to multiplayer ship selection. Fixed strange reentrant
335 * problem with cf_callback when loading freespace data
337 * 40 12/23/97 11:59a Allender
338 * changes to ship/wespon selection for multplayer. added sounds to some
339 * interface screens. Update and modiied end-of-briefing packets -- yet
342 * 39 12/23/97 11:04a Lawrance
343 * fix bug in ss_swap_slot_slot()
345 * 38 12/23/97 10:57a Lawrance
346 * move player_set_weapon_prefs() to when commit is pressed in briefing
347 * (from entering gameplay)
349 * 37 12/23/97 10:54a Lawrance
350 * fix some bugs in multiplayer ship selection
352 * 36 12/22/97 6:18p Lawrance
353 * Get save/restore of player loadout working with new code
355 * 35 12/22/97 1:40a Lawrance
356 * Re-write ship select/weapons loadout to be multiplayer friendly
358 * 34 12/19/97 1:23p Dave
359 * Put in multiplayer groundwork for new weapon/ship select screens.
365 #include "missionscreencommon.h"
366 #include "missionshipchoice.h"
367 #include "missionparse.h"
368 #include "missionbrief.h"
369 #include "freespace.h"
370 #include "gamesequence.h"
379 #include "linklist.h"
385 #include "audiostr.h"
388 #include "snazzyui.h"
389 #include "animplay.h"
390 #include "packunpack.h"
391 #include "missionweaponchoice.h"
392 #include "contexthelp.h"
395 #include "missionhotkey.h"
397 #include "multimsgs.h"
398 #include "missionload.h"
399 #include "eventmusic.h"
403 #include "multiteamselect.h"
404 #include "multiutil.h"
405 #include "hudwingmanstatus.h"
406 #include "alphacolors.h"
407 #include "localize.h"
409 //////////////////////////////////////////////////////
411 //////////////////////////////////////////////////////
412 char default_player_ship[255] = NOX("GTF Ulysses");
413 int Select_default_ship = 0;
414 int Ship_select_open = 0; // This game-wide global flag is set to 1 to indicate that the ship
415 // select screen has been opened and memory allocated. This flag
416 // is needed so we can know if ship_select_close() needs to called if
417 // restoring a game from the Options screen invoked from ship select
419 int Commit_pressed; // flag to indicate that the commit button was pressed
420 // use a flag, so the ship_create() can be done at the end of the loop
422 //////////////////////////////////////////////////////
424 //////////////////////////////////////////////////////
425 static int Ship_anim_class = -1; // ship class that is playing as an animation
426 static int Ss_delta_x, Ss_delta_y; // used to offset the carried icon to make it smoothly leave static position
428 //////////////////////////////////////////////////////
430 //////////////////////////////////////////////////////
431 typedef struct ss_icon_info
433 int icon_bmaps[NUM_ICON_FRAMES];
434 int current_icon_bitmap;
436 anim_instance_t *anim_instance;
439 typedef struct ss_slot_info
441 int status; // slot status (WING_SLOT_DISABLED, etc)
442 int sa_index; // index into ship arrival list, -1 if ship is created
443 int original_ship_class;
446 typedef struct ss_wing_info
451 ss_slot_info ss_slots[MAX_WING_SLOTS];
454 //ss_icon_info Ss_icons[MAX_SHIP_TYPES]; // holds ui info on different ship icons
455 //ss_wing_info Ss_wings[MAX_WING_BLOCKS]; // holds ui info for wings and wing slots
457 ss_wing_info Ss_wings_teams[MAX_TEAMS][MAX_WING_BLOCKS];
458 ss_wing_info *Ss_wings;
460 ss_icon_info Ss_icons_teams[MAX_TEAMS][MAX_SHIP_TYPES];
461 ss_icon_info *Ss_icons;
463 int Ss_mouse_down_on_region = -1;
465 int Selected_ss_class; // set to ship class of selected ship, -1 if none selected
466 int Hot_ss_icon; // index that icon is over in list (0..4)
467 int Hot_ss_slot; // index for slot that mouse is over (0..11)
469 ////////////////////////////////////////////////////////////
471 ////////////////////////////////////////////////////////////
472 UI_WINDOW Ship_select_ui_window;
474 static int Ship_anim_coords[GR_NUM_RESOLUTIONS][2] = {
483 static int Ship_info_coords[GR_NUM_RESOLUTIONS][2] = {
492 // coordinate lookup indicies
493 #define SHIP_SELECT_X_COORD 0
494 #define SHIP_SELECT_Y_COORD 1
495 #define SHIP_SELECT_W_COORD 2
496 #define SHIP_SELECT_H_COORD 3
499 // NK: changed from 37 to 51 for new FS2 animations
501 #define SHIP_ANIM_LOOP_FRAME 0
503 #define SHIP_ANIM_LOOP_FRAME 51
506 #define MAX_ICONS_ON_SCREEN 4
508 // (x,y) pairs for ship icon and ship icon number
509 int Ship_list_coords[GR_NUM_RESOLUTIONS][MAX_ICONS_ON_SCREEN][4] = {
524 // Store the x locations for the icons in the wing formations
525 int Wing_icon_coords[GR_NUM_RESOLUTIONS][MAX_WSS_SLOTS][2] = {
560 //////////////////////////////////////////////////////
561 // Linked List of icons to show on ship selection list
562 //////////////////////////////////////////////////////
563 #define SS_ACTIVE_ITEM_USED (1<<0)
564 typedef struct ss_active_item
566 ss_active_item *prev, *next;
571 static ss_active_item SS_active_head;
572 static ss_active_item SS_active_items[MAX_WSS_SLOTS];
574 static int SS_active_list_start;
575 static int SS_active_list_size;
577 //////////////////////////////////////////////////////
578 // Background bitmaps data for ship_select
579 //////////////////////////////////////////////////////
580 static char* Ship_select_background_fname[GR_NUM_RESOLUTIONS] = {
585 static char* Ship_select_background_mask_fname[GR_NUM_RESOLUTIONS] = {
590 int Ship_select_background_bitmap;
592 //////////////////////////////////////////////////////
593 // Ship select specific buttons
594 //////////////////////////////////////////////////////
595 #define NUM_SS_BUTTONS 4
596 #define SS_BUTTON_SCROLL_UP 0
597 #define SS_BUTTON_SCROLL_DOWN 1
598 #define SS_BUTTON_RESET 2
599 #define SS_BUTTON_DUMMY 3 // needed to capture mouse for drag/drop icons
601 // convenient struct for handling all button controls
607 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
609 ss_buttons(char *name, int x1, int y1, int xt1, int yt1, int h, int s) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h), scrollable(s) {}
612 static ss_buttons Ship_select_buttons[GR_NUM_RESOLUTIONS][NUM_SS_BUTTONS] = {
614 ss_buttons("ssb_08", 5, 303, -1, -1, 8, 0), // SCROLL UP
615 ss_buttons("ssb_09", 5, 454, -1, -1, 9, 0), // SCROLL DOWN
616 ss_buttons("ssb_39", 571, 347, -1, -1, 39,0), // RESET
617 ss_buttons("ssb_39", 0, 0, -1, -1, 99,0) // dummy for drag n' drop
620 ss_buttons("2_ssb_08", 8, 485, -1, -1, 8, 0), // SCROLL UP
621 ss_buttons("2_ssb_09", 8, 727, -1, -1, 9, 0), // SCROLL DOWN
622 ss_buttons("2_ssb_39", 913, 556, -1, -1, 39,0), // RESET
623 ss_buttons("2_ssb_39", 0, 0, -1, -1, 99,0) // dummy for drag n' drop
628 #define SHIP_SELECT_NUM_TEXT 1
629 UI_XSTR Ship_select_text[GR_NUM_RESOLUTIONS][SHIP_SELECT_NUM_TEXT] = {
631 { "Reset", 1337, 580, 337, UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[0][SS_BUTTON_RESET].button }
634 { "Reset", 1337, 938, 546, UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[1][SS_BUTTON_RESET].button }
638 // Mask bitmap pointer and Mask bitmap_id
639 static bitmap* ShipSelectMaskPtr; // bitmap pointer to the ship select mask bitmap
640 static ubyte* ShipSelectMaskData; // pointer to actual bitmap data
641 static int Shipselect_mask_w, Shipselect_mask_h;
642 static int ShipSelectMaskBitmap; // bitmap id of the ship select mask bitmap
644 static MENU_REGION Region[NUM_SHIP_SELECT_REGIONS];
645 static int Num_mask_regions;
647 //////////////////////////////////////////////////////
648 // Drag and Drop variables
649 //////////////////////////////////////////////////////
650 typedef struct ss_carry_icon_info
652 int from_slot; // slot index (0..11), -1 if carried from list
653 int ship_class; // ship class of carried icon
655 } ss_carry_icon_info;
657 ss_carry_icon_info Carried_ss_icon;
659 ////////////////////////////////////////////////////////////////////
660 // Internal function prototypes
661 ////////////////////////////////////////////////////////////////////
664 void draw_ship_icons();
665 void draw_ship_icon_with_number(int screen_offset, int ship_class);
666 void stop_ship_animation();
667 void start_ship_animation(int ship_class, int play_sound=0);
670 int pick_from_ship_list(int screen_offset, int ship_class);
671 void pick_from_wing(int wb_num, int ws_num);
674 void ship_select_button_do(int i);
675 void ship_select_common_init();
676 void ss_reset_selected_ship();
677 void ss_restore_loadout();
678 void maybe_change_selected_wing_ship(int wb_num, int ws_num);
681 void ss_init_pool(team_data *pteam);
685 void ss_unload_icons();
686 void ss_init_units();
687 void unload_ship_anim_instances();
688 void unload_ship_anims();
689 anim* ss_load_individual_animation(int ship_class);
691 // Carry icon functions
692 int ss_icon_being_carried();
693 void ss_reset_carried_icon();
694 void ss_set_carried_icon(int from_slot, int ship_class);
696 #define SHIP_DESC_X 445
697 #define SHIP_DESC_Y 273
699 char *ss_tooltip_handler(char *str)
701 if (Selected_ss_class < 0)
704 if (!stricmp(str, NOX("@ship_name"))) {
705 return Ship_info[Selected_ss_class].name;
707 } else if (!stricmp(str, NOX("@ship_type"))) {
708 return Ship_info[Selected_ss_class].type_str;
710 } else if (!stricmp(str, NOX("@ship_maneuverability"))) {
711 return Ship_info[Selected_ss_class].maneuverability_str;
713 } else if (!stricmp(str, NOX("@ship_armor"))) {
714 return Ship_info[Selected_ss_class].armor_str;
716 } else if (!stricmp(str, NOX("@ship_manufacturer"))) {
717 return Ship_info[Selected_ss_class].manufacturer_str;
719 } else if (!stricmp(str, NOX("@ship_desc"))) {
723 str = Ship_info[Selected_ss_class].desc;
727 gr_get_string_size(&w, &h, str);
728 x = SHIP_DESC_X - w / 2;
729 y = SHIP_DESC_Y - h / 2;
731 gr_set_color_fast(&Color_black);
732 gr_rect(x - 5, y - 5, w + 10, h + 10);
734 gr_set_color_fast(&Color_bright_white);
735 gr_string(x, y, str);
742 // Is an icon being carried?
743 int ss_icon_being_carried()
745 if ( Carried_ss_icon.ship_class >= 0 ) {
752 // Clear out carried icon info
753 void ss_reset_carried_icon()
755 Carried_ss_icon.from_slot = -1;
756 Carried_ss_icon.ship_class = -1;
759 // return !0 if carried icon has moved from where it was picked up
760 int ss_carried_icon_moved()
764 mouse_get_pos( &mx, &my );
765 if ( Carried_ss_icon.from_x != mx || Carried_ss_icon.from_y != my) {
772 // Set carried icon data
773 void ss_set_carried_icon(int from_slot, int ship_class)
775 Carried_ss_icon.from_slot = from_slot;
776 Carried_ss_icon.ship_class = ship_class;
778 // Set the mouse to captured
779 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.capture_mouse();
782 // clear all active list items, and reset the flags inside the SS_active_items[] array
783 void clear_active_list()
786 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
787 SS_active_items[i].flags = 0;
788 SS_active_items[i].ship_class = -1;
790 list_init(&SS_active_head);
792 SS_active_list_start = 0;
793 SS_active_list_size = 0;
796 // get a free element from SS_active_items[]
797 ss_active_item *get_free_active_list_node()
800 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
801 if ( SS_active_items[i].flags == 0 ) {
802 SS_active_items[i].flags |= SS_ACTIVE_ITEM_USED;
803 return &SS_active_items[i];
809 // add a ship into the active list
810 void active_list_add(int ship_class)
814 sai = get_free_active_list_node();
816 sai->ship_class = ship_class;
817 list_append(&SS_active_head, sai);
820 // remove a ship from the active list
821 void active_list_remove(int ship_class)
823 ss_active_item *sai, *temp;
825 // next store players not assigned to wings
826 sai = GET_FIRST(&SS_active_head);
828 while(sai != END_OF_LIST(&SS_active_head)){
829 temp = GET_NEXT(sai);
830 if ( sai->ship_class == ship_class ) {
831 list_remove(&SS_active_head, sai);
838 // Build up the ship selection active list, which is a list of all ships that the player
840 void init_active_list()
847 // build the active list
848 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
849 if ( Ss_pool[i] > 0 ) {
850 sai = get_free_active_list_node();
853 list_append(&SS_active_head, sai);
854 SS_active_list_size++;
860 void ship_select_check_buttons()
865 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
866 b = &Ship_select_buttons[gr_screen.res][i];
867 if ( b->button.pressed() ) {
868 ship_select_button_do(b->hotspot);
873 // reset the ship selection to the mission defaults
874 void ss_reset_to_default()
876 if ( Game_mode & GM_MULTIPLAYER ) {
881 stop_ship_animation();
883 ss_init_pool(&Team_data[Common_team]);
886 ss_reset_selected_ship();
887 ss_reset_carried_icon();
890 wl_reset_to_defaults();
892 start_ship_animation(Selected_ss_class, 1);
895 // -------------------------------------------------------------------
896 // ship_select_redraw_pressed_buttons()
898 // Redraw any ship select buttons that are pressed down. This function is needed
899 // since we sometimes need to draw pressed buttons last to ensure the entire
900 // button gets drawn (and not overlapped by other buttons)
902 void ship_select_redraw_pressed_buttons()
907 common_redraw_pressed_buttons();
909 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
910 b = &Ship_select_buttons[gr_screen.res][i];
911 if ( b->button.pressed() ) {
912 b->button.draw_forced(2);
917 void ship_select_buttons_init()
922 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
923 b = &Ship_select_buttons[gr_screen.res][i];
924 b->button.create( &Ship_select_ui_window, "", b->x, b->y, 60, 30, b->scrollable);
925 // set up callback for when a mouse first goes over a button
926 b->button.set_highlight_action( common_play_highlight_sound );
927 b->button.set_bmaps(b->filename);
928 b->button.link_hotspot(b->hotspot);
932 for(i=0; i<SHIP_SELECT_NUM_TEXT; i++){
933 Ship_select_ui_window.add_XSTR(&Ship_select_text[gr_screen.res][i]);
936 // We don't want to have the reset button appear in multiplayer
937 if ( Game_mode & GM_MULTIPLAYER ) {
938 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.disable();
939 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.hide();
942 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.disable();
943 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.hide();
946 // -------------------------------------------------------------------------------------
947 // ship_select_button_do() do the button action for the specified pressed button
949 void ship_select_button_do(int i)
951 if ( Background_playing )
955 case SHIP_SELECT_SHIP_SCROLL_UP:
956 if ( Current_screen != ON_SHIP_SELECT )
959 if ( common_scroll_down_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
960 gamesnd_play_iface(SND_SCROLL);
962 gamesnd_play_iface(SND_GENERAL_FAIL);
966 case SHIP_SELECT_SHIP_SCROLL_DOWN:
967 if ( Current_screen != ON_SHIP_SELECT )
970 if ( common_scroll_up_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
971 gamesnd_play_iface(SND_SCROLL);
973 gamesnd_play_iface(SND_GENERAL_FAIL);
978 case SHIP_SELECT_RESET:
979 ss_reset_to_default();
984 // ---------------------------------------------------------------------
985 // ship_select_init() is called once when the ship select screen begins
988 void ship_select_init()
990 common_set_interface_palette("ShipPalette");
991 common_flash_button_init();
993 // if in multiplayer -- set my state to be ship select
994 if ( Game_mode & GM_MULTIPLAYER ){
995 // also set the ship which is mine as the default
996 maybe_change_selected_wing_ship(Net_player->p_info.ship_index/4,Net_player->p_info.ship_index % 4);
999 set_active_ui(&Ship_select_ui_window);
1000 Current_screen = ON_SHIP_SELECT;
1002 Ss_mouse_down_on_region = -1;
1004 help_overlay_set_state(SS_OVERLAY,0);
1006 if ( Ship_select_open ) {
1007 start_ship_animation( Selected_ss_class );
1008 common_buttons_maybe_reload(&Ship_select_ui_window); // AL 11-21-97: this is necessary since we may returning from the hotkey
1009 // screen, which can release common button bitmaps.
1010 common_reset_buttons();
1011 nprintf(("Alan","ship_select_init() returning without doing anything\n"));
1015 nprintf(("Alan","entering ship_select_init()\n"));
1016 common_select_init();
1018 ShipSelectMaskBitmap = bm_load(Ship_select_background_mask_fname[gr_screen.res]);
1019 if (ShipSelectMaskBitmap < 0) {
1020 if (gr_screen.res == GR_640) {
1021 Error(LOCATION,"Could not load in 'shipselect-m'!");
1022 } else if (gr_screen.res == GR_1024) {
1023 Error(LOCATION,"Could not load in '2_shipselect-m'!");
1027 Shipselect_mask_w = -1;
1028 Shipselect_mask_h = -1;
1030 // get a pointer to bitmap by using bm_lock()
1031 ShipSelectMaskPtr = bm_lock(ShipSelectMaskBitmap, 8, BMP_AABITMAP);
1032 ShipSelectMaskData = (ubyte*)ShipSelectMaskPtr->data;
1033 bm_get_info(ShipSelectMaskBitmap, &Shipselect_mask_w, &Shipselect_mask_h);
1035 help_overlay_load(SS_OVERLAY);
1037 // Set up the mask regions
1038 // initialize the different regions of the menu that will react when the mouse moves over it
1039 Num_mask_regions = 0;
1041 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_BRIEFING_REGION, 0);
1042 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_SS_REGION, 0);
1043 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_WEAPON_REGION, 0);
1044 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_COMMIT_REGION, 0);
1045 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_HELP_REGION, 0);
1046 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_OPTIONS_REGION, 0);
1048 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_UP, 0);
1049 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_DOWN, 0);
1051 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_0, 0);
1052 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_1, 0);
1053 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_2, 0);
1054 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_3, 0);
1056 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_0, 0);
1057 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_1, 0);
1058 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_2, 0);
1059 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_3, 0);
1060 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_0, 0);
1061 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_1, 0);
1062 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_2, 0);
1063 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_3, 0);
1064 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_0, 0);
1065 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_1, 0);
1066 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_2, 0);
1067 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_3, 0);
1069 Ship_select_open = 1; // This game-wide global flag is set to 1 to indicate that the ship
1070 // select screen has been opened and memory allocated. This flag
1071 // is needed so we can know if ship_select_close() needs to called if
1072 // restoring a game from the Options screen invoked from ship select
1074 // init ship selection masks and buttons
1075 Ship_select_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1076 Ship_select_ui_window.set_mask_bmap(Ship_select_background_mask_fname[gr_screen.res]);
1077 Ship_select_ui_window.tooltip_handler = ss_tooltip_handler;
1078 common_buttons_init(&Ship_select_ui_window);
1079 ship_select_buttons_init();
1080 start_ship_animation( Selected_ss_class );
1082 // init ship selection background bitmpa
1083 Ship_select_background_bitmap = bm_load(Ship_select_background_fname[gr_screen.res]);
1087 // Return the ship class for the icon specified by index. Need to iterate through the active
1088 // list of icons to find out what ship class for this icon
1090 // input: index => list index (0..3)
1091 // exit: ship class, -1 if none
1093 int ss_get_ship_class_from_list(int index)
1095 ss_active_item *sai;
1096 int list_entry, i, count;
1101 for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1103 if ( count <= SS_active_list_start )
1106 if ( i >= MAX_ICONS_ON_SCREEN )
1110 list_entry = sai->ship_class;
1120 // ---------------------------------------------------------------------
1121 // maybe_pick_up_list_icon()
1123 void maybe_pick_up_list_icon(int offset)
1127 ship_class = ss_get_ship_class_from_list(offset);
1128 if ( ship_class != -1 ) {
1129 pick_from_ship_list(offset, ship_class);
1133 // ---------------------------------------------------------------------
1134 // maybe_change_selected_ship()
1136 void maybe_change_selected_ship(int offset)
1140 ship_class = ss_get_ship_class_from_list(offset);
1141 if ( ship_class == -1 )
1144 if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+offset) ) {
1148 if ( Selected_ss_class == -1 ) {
1149 Selected_ss_class = ship_class;
1150 start_ship_animation(Selected_ss_class, 1);
1152 else if ( Selected_ss_class != ship_class ) {
1153 Selected_ss_class = ship_class;
1154 start_ship_animation(Selected_ss_class, 1);
1157 Assert( Selected_ss_class == ship_class );
1160 void maybe_change_selected_wing_ship(int wb_num, int ws_num)
1162 ss_slot_info *ss_slot;
1164 Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
1165 Assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS);
1167 if ( Ss_wings[wb_num].wingnum < 0 ) {
1171 ss_slot = &Ss_wings[wb_num].ss_slots[ws_num];
1172 switch ( ss_slot->status & ~WING_SLOT_LOCKED ) {
1174 case WING_SLOT_FILLED:
1175 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
1176 if ( Selected_ss_class != -1 && Selected_ss_class != Wss_slots[wb_num*4+ws_num].ship_class ) {
1177 Selected_ss_class = Wss_slots[wb_num*4+ws_num].ship_class;
1178 start_ship_animation(Selected_ss_class, 1);
1188 // ---------------------------------------------------------------------
1189 // do_mouse_over_wing_slot()
1191 // returns: 0 => icon wasn't dropped onto slot
1192 // 1 => icon was dropped onto slot
1193 int do_mouse_over_wing_slot(int block, int slot)
1195 Hot_ss_slot = block*4 + slot;
1197 if ( !mouse_down(MOUSE_LEFT_BUTTON) ) {
1198 if ( ss_icon_being_carried() ) {
1200 if ( ss_disabled_slot(block*4+slot) ) {
1201 gamesnd_play_iface(SND_ICON_DROP);
1205 if ( !ss_carried_icon_moved() ) {
1206 ss_reset_carried_icon();
1210 ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, Hot_ss_slot, -1);
1211 ss_reset_carried_icon();
1215 if ( Ss_mouse_down_on_region == (WING_0_SHIP_0+block*4+slot) ) {
1216 pick_from_wing(block, slot);
1223 void do_mouse_over_list_slot(int index)
1225 Hot_ss_icon = index;
1227 if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+index) ){
1231 if ( mouse_down(MOUSE_LEFT_BUTTON) )
1232 maybe_pick_up_list_icon(index);
1235 // Icon has been dropped, but not onto a wing slot
1236 void ss_maybe_drop_icon()
1238 if ( Drop_icon_mflag ) {
1239 if ( ss_icon_being_carried() ) {
1240 // Add back into the ship entry list
1241 if ( Carried_ss_icon.from_slot >= 0 ) {
1243 ss_drop(Carried_ss_icon.from_slot, -1, -1, Carried_ss_icon.ship_class);
1245 if ( ss_carried_icon_moved() ) {
1246 gamesnd_play_iface(SND_ICON_DROP);
1249 ss_reset_carried_icon();
1254 void ss_anim_pause()
1256 if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1257 anim_pause(Ss_icons[Selected_ss_class].anim_instance);
1261 void ss_anim_unpause()
1263 if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1264 anim_unpause(Ss_icons[Selected_ss_class].anim_instance);
1268 // maybe flash a button if player hasn't done anything for a while
1269 void ss_maybe_flash_button()
1271 if ( common_flash_bright() ) {
1272 // weapon loadout button
1273 if ( Common_buttons[Current_screen-1][gr_screen.res][2].button.button_hilighted() ) {
1274 common_flash_button_init();
1276 Common_buttons[Current_screen-1][gr_screen.res][2].button.draw_forced(1);
1282 // -------------------------------------------------------------------------------------
1283 // ship_select_render(float frametime)
1285 void ship_select_render(float frametime)
1287 if ( !Background_playing ) {
1288 gr_set_bitmap(Ship_select_background_bitmap);
1292 anim_render_all(0, frametime);
1293 anim_render_all(ON_SHIP_SELECT, frametime);
1297 // blit any active ship information text
1298 void ship_select_blit_ship_info()
1303 color *header = &Color_white;
1304 color *text = &Color_green;
1307 // if we don't have a valid ship selected, do nothing
1308 if(Selected_ss_class == -1){
1312 // get the ship class
1313 sip = &Ship_info[Selected_ss_class];
1316 y_start = Ship_info_coords[gr_screen.res][SHIP_SELECT_Y_COORD];
1320 // blit the ship class (name)
1321 gr_set_color_fast(header);
1322 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Class",739));
1324 if(strlen(sip->name)){
1325 gr_set_color_fast(text);
1326 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->name);
1330 // blit the ship type
1331 gr_set_color_fast(header);
1332 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Type",740));
1334 if((sip->type_str != NULL) && strlen(sip->type_str)){
1335 gr_set_color_fast(text);
1336 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->type_str);
1340 // blit the ship length
1341 gr_set_color_fast(header);
1342 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Length",741));
1344 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1346 // in german, drop the s from Meters and make sure M is caps
1347 char *sp = strstr(sip->ship_length, "Meters");
1349 sp[5] = ' '; // make the old s a space now
1352 gr_set_color_fast(text);
1353 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start, sip->ship_length);
1357 // blit the max velocity
1358 gr_set_color_fast(header);
1359 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Max Velocity",742));
1361 sprintf(str,XSTR("%d m/s",743),(int)sip->max_vel.z);
1362 gr_set_color_fast(text);
1363 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,str);
1366 // blit the maneuverability
1367 gr_set_color_fast(header);
1368 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Maneuverability",744));
1370 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1371 gr_set_color_fast(text);
1372 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->maneuverability_str);
1377 gr_set_color_fast(header);
1378 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Armor",745));
1380 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1381 gr_set_color_fast(text);
1382 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->armor_str);
1386 // blit the gun mounts
1387 gr_set_color_fast(header);
1388 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Gun Mounts",746));
1390 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1391 gr_set_color_fast(text);
1392 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->gun_mounts);
1396 // blit the missile banke
1397 gr_set_color_fast(header);
1398 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Missile Banks",747));
1400 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1401 gr_set_color_fast(text);
1402 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->missile_banks);
1406 // blit the manufacturer
1407 gr_set_color_fast(header);
1408 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Manufacturer",748));
1410 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1411 gr_set_color_fast(text);
1412 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->manufacturer_str);
1416 // blit the _short_ text description
1418 Assert(Multi_ts_ship_info_line_count < 3);
1419 gr_set_color_fast(&Color_normal);
1420 for(idx=0;idx<SHIP_SELECT_ship_info_line_count;idx++){
1421 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start, SHIP_SELECT_ship_info_lines[idx]);
1428 // ---------------------------------------------------------------------
1429 // ship_select_do() is called once per game frame, and is responsible for
1430 // updating the ship select screen
1432 // frametime is in seconds
1433 void ship_select_do(float frametime)
1435 int k, ship_select_choice, snazzy_action;
1437 ship_select_choice = snazzy_menu_do(ShipSelectMaskData, Shipselect_mask_w, Shipselect_mask_h, Num_mask_regions, Region, &snazzy_action, 0);
1442 k = common_select_do(frametime);
1444 if ( help_overlay_active(SS_OVERLAY) ) {
1451 // Check common keypresses
1452 common_check_keys(k);
1454 if ( Mouse_down_last_frame ) {
1455 Ss_mouse_down_on_region = ship_select_choice;
1458 // Check for the mouse over a region (not clicked, just over)
1459 if ( ship_select_choice > -1 ) {
1461 switch(ship_select_choice) {
1462 case SHIP_SELECT_ICON_0:
1463 do_mouse_over_list_slot(0);
1465 case SHIP_SELECT_ICON_1:
1466 do_mouse_over_list_slot(1);
1468 case SHIP_SELECT_ICON_2:
1469 do_mouse_over_list_slot(2);
1471 case SHIP_SELECT_ICON_3:
1472 do_mouse_over_list_slot(3);
1475 if ( do_mouse_over_wing_slot(0,0) )
1476 ship_select_choice = -1;
1479 if ( do_mouse_over_wing_slot(0,1) )
1480 ship_select_choice = -1;
1483 if ( do_mouse_over_wing_slot(0,2) )
1484 ship_select_choice = -1;
1487 if ( do_mouse_over_wing_slot(0,3) )
1488 ship_select_choice = -1;
1491 if ( do_mouse_over_wing_slot(1,0) )
1492 ship_select_choice = -1;
1495 if ( do_mouse_over_wing_slot(1,1) )
1496 ship_select_choice = -1;
1499 if ( do_mouse_over_wing_slot(1,2) )
1500 ship_select_choice = -1;
1503 if ( do_mouse_over_wing_slot(1,3) )
1504 ship_select_choice = -1;
1507 if ( do_mouse_over_wing_slot(2,0) )
1508 ship_select_choice = -1;
1511 if ( do_mouse_over_wing_slot(2,1) )
1512 ship_select_choice = -1;
1515 if ( do_mouse_over_wing_slot(2,2) )
1516 ship_select_choice = -1;
1519 if ( do_mouse_over_wing_slot(2,3) )
1520 ship_select_choice = -1;
1529 common_check_buttons();
1530 ship_select_check_buttons();
1532 // Check for the mouse clicks over a region
1533 if ( ship_select_choice > -1 && snazzy_action == SNAZZY_CLICKED ) {
1534 switch (ship_select_choice) {
1536 case SHIP_SELECT_ICON_0:
1537 maybe_change_selected_ship(0);
1540 case SHIP_SELECT_ICON_1:
1541 maybe_change_selected_ship(1);
1544 case SHIP_SELECT_ICON_2:
1545 maybe_change_selected_ship(2);
1548 case SHIP_SELECT_ICON_3:
1549 maybe_change_selected_ship(3);
1553 maybe_change_selected_wing_ship(0,0);
1557 maybe_change_selected_wing_ship(0,1);
1561 maybe_change_selected_wing_ship(0,2);
1565 maybe_change_selected_wing_ship(0,3);
1569 maybe_change_selected_wing_ship(1,0);
1573 maybe_change_selected_wing_ship(1,1);
1577 maybe_change_selected_wing_ship(1,2);
1581 maybe_change_selected_wing_ship(1,3);
1585 maybe_change_selected_wing_ship(2,0);
1589 maybe_change_selected_wing_ship(2,1);
1593 maybe_change_selected_wing_ship(2,2);
1597 maybe_change_selected_wing_ship(2,3);
1606 ss_maybe_drop_icon();
1608 if ( Ship_anim_class >= 0) {
1609 Assert(Selected_ss_class >= 0);
1610 if ( Ss_icons[Selected_ss_class].anim_instance->frame_num == Ss_icons[Selected_ss_class].anim_instance->stop_at ) {
1611 nprintf(("anim", "Frame number = %d, Stop at %d\n", Ss_icons[Selected_ss_class].anim_instance->frame_num, Ss_icons[Selected_ss_class].anim_instance->stop_at));
1612 anim_play_struct aps;
1613 anim_release_render_instance(Ss_icons[Selected_ss_class].anim_instance);
1614 anim_play_init(&aps, Ss_icons[Selected_ss_class].anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1615 aps.start_at = SHIP_ANIM_LOOP_FRAME;
1616 // aps.start_at = 0;
1617 aps.screen_id = ON_SHIP_SELECT;
1618 aps.framerate_independent = 1;
1619 aps.skip_frames = 0;
1620 Ss_icons[Selected_ss_class].anim_instance = anim_play(&aps);
1626 ship_select_render(frametime);
1627 if ( !Background_playing ) {
1628 Ship_select_ui_window.draw();
1629 ship_select_redraw_pressed_buttons();
1630 common_render_selected_screen_button();
1633 // The background transition plays once. Display ship icons after Background done playing
1634 if ( !Background_playing ) {
1636 for ( int i = 0; i < MAX_WING_BLOCKS; i++ ) {
1637 draw_wing_block(i, Hot_ss_slot, -1, Selected_ss_class);
1641 if ( ss_icon_being_carried() ) {
1642 int mouse_x, mouse_y;
1643 mouse_get_pos( &mouse_x, &mouse_y );
1644 gr_set_bitmap(Ss_icons[Carried_ss_icon.ship_class].icon_bmaps[ICON_FRAME_SELECTED]);
1645 gr_bitmap(mouse_x + Ss_delta_x , mouse_y + Ss_delta_y);
1648 // draw out ship information
1649 ship_select_blit_ship_info();
1652 ss_maybe_flash_button();
1654 // blit help overlay if active
1655 help_overlay_maybe_blit(SS_OVERLAY);
1657 // If the commit button was pressed, do the commit button actions. Done at the end of the
1658 // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1659 // the ship model is not in memory
1660 if ( Commit_pressed ) {
1667 if ( Game_mode & GM_MULTIPLAYER ) {
1668 if ( Selected_ss_class >= 0 )
1669 Net_player->p_info.ship_class = Selected_ss_class;
1672 if(!Background_playing){
1673 // should render this as close to last as possible so it overlaps all controls
1674 // chatbox_render();
1677 // If the commit button was pressed, do the commit button actions. Done at the end of the
1678 // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1679 // the ship model is not in memory
1680 if ( Commit_pressed ) {
1687 // ------------------------------------------------------------------------
1688 // ship_select_close() is called once when the ship select screen is exited
1691 void ship_select_close()
1695 if ( !Ship_select_open ) {
1696 nprintf(("Alan","ship_select_close() returning without doing anything\n"));
1700 nprintf(("Alan", "Entering ship_select_close()\n"));
1702 // done with the bitmaps, so unlock it
1703 bm_unlock(ShipSelectMaskBitmap);
1705 // unload the bitmaps
1706 bm_unload(ShipSelectMaskBitmap);
1707 help_overlay_unload(SS_OVERLAY);
1709 // release the bitmpas that were previously extracted from anim files
1712 // Release any active ship anim instances
1713 unload_ship_anim_instances();
1715 // unload ship animations if they were loaded
1716 unload_ship_anims();
1718 Ship_select_ui_window.destroy();
1720 Ship_anim_class = -1;
1721 Ship_select_open = 0; // This game-wide global flag is set to 0 to indicate that the ship
1722 // select screen has been closed and memory freed. This flag
1723 // is needed so we can know if ship_select_close() needs to called if
1724 // restoring a game from the Options screen invoked from ship select
1727 // ss_unload_icons() frees the bitmaps used for ship icons
1728 void ss_unload_icons()
1733 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1734 icon = &Ss_icons[i];
1736 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
1737 if ( icon->icon_bmaps[j] >= 0 ) {
1738 bm_release(icon->icon_bmaps[j]);
1739 icon->icon_bmaps[j] = -1;
1745 // ------------------------------------------------------------------------
1746 // draw_ship_icons() will request which icons to draw on screen.
1747 void draw_ship_icons()
1752 ss_active_item *sai;
1754 for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1756 if ( count <= SS_active_list_start )
1759 if ( i >= MAX_ICONS_ON_SCREEN )
1762 draw_ship_icon_with_number(i, sai->ship_class);
1767 // ------------------------------------------------------------------------
1768 // draw_ship_icon_with_number() will draw a ship icon on screen with the
1769 // number of available ships to the left.
1772 void draw_ship_icon_with_number(int screen_offset, int ship_class)
1776 ss_icon_info *ss_icon;
1779 Assert( screen_offset >= 0 && screen_offset <= 3 );
1780 Assert( ship_class >= 0 );
1781 ss_icon = &Ss_icons[ship_class];
1783 num_x = Ship_list_coords[gr_screen.res][screen_offset][2];
1784 num_y = Ship_list_coords[gr_screen.res][screen_offset][3];
1786 // assume default bitmap is to be used
1787 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_NORMAL];
1789 // next check if ship has mouse over it
1790 if ( Hot_ss_icon > -1 ) {
1791 Assert(Hot_ss_icon <= 3);
1792 if ( Hot_ss_icon == screen_offset )
1793 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_HOT];
1796 // highest precedence is if the ship is selected
1797 if ( Selected_ss_class > -1 ) {
1798 if ( Selected_ss_class == ship_class )
1799 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_SELECTED];
1802 if ( Ss_pool[ship_class] <= 0 ) {
1807 gr_set_bitmap(ss_icon->current_icon_bitmap);
1808 gr_bitmap(Ship_list_coords[gr_screen.res][screen_offset][0], Ship_list_coords[gr_screen.res][screen_offset][1]);
1811 sprintf(buf, "%d", Ss_pool[ship_class] );
1812 gr_set_color_fast(&Color_white);
1813 gr_string(num_x, num_y, buf);
1816 // ------------------------------------------------------------------------
1817 // stop_ship_animation() will halt the currently playing ship animation. The
1818 // instance will be freed, (but the compressed data is not freed). The animation
1819 // will not display after this function is called (even on this frame), since
1820 // the instance is removed from the anim_render_list.
1821 void stop_ship_animation()
1823 ss_icon_info *ss_icon;
1825 if ( Ship_anim_class == -1 )
1828 ss_icon = &Ss_icons[Ship_anim_class];
1830 anim_release_render_instance(ss_icon->anim_instance);
1831 ss_icon->anim_instance = NULL;
1833 Ship_anim_class = -1;
1837 // ------------------------------------------------------------------------
1838 // this loads an individual animation file
1839 // it attempts to load a hires version (ie, it attaches a "2_" in front of the
1840 // filename. if no hires version is available, it defaults to the lowres
1842 anim* ss_load_individual_animation(int ship_class)
1845 char animation_filename[CF_MAX_FILENAME_LENGTH+4];
1848 // If we are in 1024x768, we first want to append "2_" in front of the filename
1849 if (gr_screen.res == GR_1024) {
1850 Assert(strlen(Ship_info[ship_class].anim_filename) <= 30);
1851 strcpy(animation_filename, "2_");
1852 strcat(animation_filename, Ship_info[ship_class].anim_filename);
1853 // now check if file exists
1854 // GRR must add a .ANI at the end for detection
1855 strcat(animation_filename, ".ani");
1857 p_anim = anim_load(animation_filename, 1);
1858 if (p_anim == NULL) {
1859 // failed loading hi-res, revert to low res
1860 strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1861 p_anim = anim_load(animation_filename, 1);
1862 mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename));
1864 mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1867 // this is lame and doesnt work cuz cf_exist() doesnt search the packfiles
1868 if (!cf_exist(animation_filename, CF_TYPE_INTERFACE)) {
1869 // file does not exist, use original low res version
1870 strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1871 mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename));
1873 animation_filename[strlen(animation_filename) - 4] = '\0';
1874 mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1878 strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1879 p_anim = anim_load(animation_filename, 1);
1885 // ------------------------------------------------------------------------
1886 // start_ship_animation() will start a ship animation playing, and will
1887 // load the compressed anim from disk if required.
1888 void start_ship_animation(int ship_class, int play_sound)
1890 ss_icon_info *ss_icon;
1891 Assert( ship_class >= 0 );
1893 if ( Ship_anim_class == ship_class )
1896 if ( Ship_anim_class >= 0 ) {
1897 stop_ship_animation();
1900 ss_icon = &Ss_icons[ship_class];
1902 // see if we need to load in the animation from disk
1903 if ( ss_icon->anim == NULL ) {
1904 ss_icon->anim = ss_load_individual_animation(ship_class);
1907 // see if we need to get an instance
1908 if ( ss_icon->anim_instance == NULL ) {
1909 anim_play_struct aps;
1911 anim_play_init(&aps, ss_icon->anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1912 aps.screen_id = ON_SHIP_SELECT;
1913 aps.framerate_independent = 1;
1914 aps.skip_frames = 0;
1915 ss_icon->anim_instance = anim_play(&aps);
1918 Ship_anim_class = ship_class;
1920 // if ( play_sound ) {
1921 gamesnd_play_iface(SND_SHIP_ICON_CHANGE);
1925 // ------------------------------------------------------------------------
1926 // unload_ship_anims() will free all compressed anims from memory that were
1927 // loaded for the ship animations.
1930 void unload_ship_anims()
1932 for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1933 if ( Ss_icons[i].anim ) {
1934 anim_free(Ss_icons[i].anim);
1935 Ss_icons[i].anim = NULL;
1940 // ------------------------------------------------------------------------
1941 // unload_ship_anim_instances() will free any active ship animation instances.
1944 void unload_ship_anim_instances()
1946 for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1947 if ( Ss_icons[i].anim_instance ) {
1948 anim_release_render_instance(Ss_icons[i].anim_instance);
1949 Ss_icons[i].anim_instance = NULL;
1954 // ------------------------------------------------------------------------
1955 // commit_pressed() is called when the commit button from any of the briefing/ship select/ weapon
1956 // select screens is pressed. The ship selected is created, and the interface music is stopped.
1957 void commit_pressed()
1959 int player_ship_info_index;
1961 if ( Wss_num_wings > 0 ) {
1962 if(!(Game_mode & GM_MULTIPLAYER)){
1964 rc = create_wings();
1966 gamesnd_play_iface(SND_GENERAL_FAIL);
1973 if ( Selected_ss_class == -1 ) {
1974 player_ship_info_index = Team_data[Common_team].default_ship;
1977 Assert(Selected_ss_class >= 0 );
1978 player_ship_info_index = Selected_ss_class;
1981 update_player_ship( player_ship_info_index );
1982 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[0]) == -1 ) {
1983 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
1988 // Check to ensure that the hotkeys are still pointing to valid objects. It is possible
1989 // for the player to assign a ship to a hotkey, then go and delete that ship in the
1990 // ship selection, and then try to start the mission. This function will detect those objects,
1991 // and remove them from the hotkey linked lists.
1992 mission_hotkey_validate();
1994 gamesnd_play_iface(SND_COMMIT_PRESSED);
1996 // save the player loadout
1997 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1998 strcpy(Player_loadout.filename, Game_current_mission_filename);
1999 strcpy(Player_loadout.last_modified, The_mission.modified);
2003 // move to the next stage
2004 // in multiplayer this is the final mission sync
2005 if(Game_mode & GM_MULTIPLAYER){
2006 Multi_sync_mode = MULTI_SYNC_POST_BRIEFING;
2007 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2009 // otherwise tell the standalone to move everyone into this state and continue
2010 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2011 send_mission_sync_packet(MULTI_SYNC_POST_BRIEFING);
2014 // in single player we jump directly into the mission
2016 gameseq_post_event(GS_EVENT_ENTER_GAME);
2020 // ------------------------------------------------------------------------
2021 // pick_from_ship_list() will determine if an icon from the ship selection
2022 // list can be picked up (for drag and drop). It calculates the difference
2023 // in x & y between the icon and the mouse, so we can move the icon with the
2024 // mouse in a realistic way
2025 int pick_from_ship_list(int screen_offset, int ship_class)
2028 Assert(ship_class >= 0);
2030 if ( Wss_num_wings == 0 )
2033 // If carrying an icon, then do nothing
2034 if ( ss_icon_being_carried() )
2037 if ( Ss_pool[ship_class] > 0 ) {
2038 int mouse_x, mouse_y;
2040 ss_set_carried_icon(-1, ship_class);
2041 mouse_get_pos( &mouse_x, &mouse_y );
2042 Ss_delta_x = Ship_list_coords[gr_screen.res][screen_offset][0] - mouse_x;
2043 Ss_delta_y = Ship_list_coords[gr_screen.res][screen_offset][1] - mouse_y;
2044 Assert( Ss_pool[ship_class] >= 0 );
2048 common_flash_button_init();
2052 // ------------------------------------------------------------------------
2053 // pick_from_wing() will determine if an icon from the wing formation (wb_num)
2054 // and slot number (ws_num) can be picked up (for drag and drop). It calculates
2055 // the difference in x & y between the icon and the mouse, so we can move the icon with the
2056 // mouse in a realistic way
2057 void pick_from_wing(int wb_num, int ws_num)
2060 Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
2061 Assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS);
2065 wb = &Ss_wings[wb_num];
2066 ws = &wb->ss_slots[ws_num];
2067 slot_index = wb_num*4+ws_num;
2069 if ( wb->wingnum < 0 )
2072 // Take care of case where the mouse button goes from up to down in one frame while
2074 if ( Drop_on_wing_mflag && ss_icon_being_carried() ) {
2075 if ( !ss_disabled_slot(slot_index) ) {
2076 ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, slot_index, -1);
2077 ss_reset_carried_icon();
2078 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2082 if ( ss_icon_being_carried() )
2085 if ( ss_disabled_slot(slot_index) ) {
2089 switch ( ws->status ) {
2090 case WING_SLOT_DISABLED:
2091 case WING_SLOT_IGNORE:
2095 case WING_SLOT_EMPTY:
2096 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2097 // TODO: add fail sound
2101 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2102 case WING_SLOT_FILLED:
2104 int mouse_x, mouse_y;
2105 Assert(Wss_slots[slot_index].ship_class >= 0);
2106 ss_set_carried_icon(slot_index, Wss_slots[slot_index].ship_class);
2108 mouse_get_pos( &mouse_x, &mouse_y );
2109 Ss_delta_x = Wing_icon_coords[gr_screen.res][slot_index][0] - mouse_x;
2110 Ss_delta_y = Wing_icon_coords[gr_screen.res][slot_index][1] - mouse_y;
2111 Carried_ss_icon.from_x = mouse_x;
2112 Carried_ss_icon.from_y = mouse_y;
2122 common_flash_button_init();
2125 // ------------------------------------------------------------------------
2126 // draw_wing_block() will draw the wing icons for the wing formation number
2127 // passed in as a parameter.
2129 // input: wb_num => wing block number (numbering starts at 0)
2130 // hot_slot => index of slot that mouse is over
2131 // selected_slot => index of slot that is selected
2132 // class_select => all ships of this class are drawn selected (send -1 to not use)
2133 void draw_wing_block(int wb_num, int hot_slot, int selected_slot, int class_select)
2139 int i, bitmap_to_draw, w, h, sx, sy, slot_index;
2141 Assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
2142 wb = &Ss_wings[wb_num];
2144 if ( wb->wingnum == -1 )
2147 // print the wing name under the wing
2148 wp = &Wings[wb->wingnum];
2149 gr_get_string_size(&w, &h, wp->name);
2150 sx = Wing_icon_coords[gr_screen.res][wb_num*4][0] + 16 - w/2;
2151 sy = Wing_icon_coords[gr_screen.res][wb_num*4 + 3][1] + 32 + h;
2152 gr_set_color_fast(&Color_normal);
2153 gr_string(sx, sy, wp->name);
2155 for ( i = 0; i < MAX_WING_SLOTS; i++ ) {
2156 bitmap_to_draw = -1;
2157 ws = &wb->ss_slots[i];
2158 slot_index = wb_num*4 + i;
2160 if ( Wss_slots[slot_index].ship_class >= 0 ) {
2161 icon = &Ss_icons[Wss_slots[slot_index].ship_class];
2166 switch(ws->status & ~WING_SLOT_LOCKED ) {
2167 case WING_SLOT_FILLED:
2168 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2172 if ( class_select >= 0 ) { // only ship select
2173 if ( Carried_ss_icon.from_slot == slot_index ) {
2174 if ( ss_carried_icon_moved() ) {
2175 bitmap_to_draw = Wing_slot_empty_bitmap;
2177 bitmap_to_draw = -1;
2183 if ( ws->status & WING_SLOT_LOCKED ) {
2184 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2186 // in multiplayer, determine if this it the special case where the slot is disabled, and
2187 // it is also _my_ slot (ie, team capatains/host have not locked players yet)
2188 if((Game_mode & GM_MULTIPLAYER) && multi_ts_disabled_high_slot(slot_index)){
2189 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED_HIGH];
2195 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_NORMAL];
2196 if ( selected_slot == slot_index || class_select == Wss_slots[slot_index].ship_class) {
2197 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2198 } else if ( hot_slot == slot_index ) {
2199 if ( mouse_down(MOUSE_LEFT_BUTTON) ){
2200 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2202 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_HOT];
2206 if ( ws->status & WING_SLOT_IS_PLAYER && (selected_slot != slot_index) ) {
2207 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_PLAYER];
2211 case WING_SLOT_EMPTY:
2212 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2213 bitmap_to_draw = Wing_slot_empty_bitmap;
2216 case WING_SLOT_DISABLED:
2217 case WING_SLOT_IGNORE:
2219 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2221 bitmap_to_draw = Wing_slot_disabled_bitmap;
2232 if ( bitmap_to_draw != -1 ) {
2233 gr_set_bitmap(bitmap_to_draw);
2234 gr_bitmap(Wing_icon_coords[gr_screen.res][slot_index][0], Wing_icon_coords[gr_screen.res][slot_index][1]);
2239 // called by multiplayer team select to set the slot based flags
2240 void ss_make_slot_empty(int slot_index)
2242 int wing_num,slot_num;
2246 // calculate the wing #
2247 wing_num = slot_index / 4;
2248 slot_num = slot_index % 4;
2250 // get the wing and slot entries
2251 wb = &Ss_wings[wing_num];
2252 ws = &wb->ss_slots[slot_num];
2255 ws->status &= ~(WING_SLOT_FILLED | WING_SLOT_DISABLED);
2256 ws->status |= WING_SLOT_EMPTY;
2259 // called by multiplayer team select to set the slot based flags
2260 void ss_make_slot_full(int slot_index)
2262 int wing_num,slot_num;
2266 // calculate the wing #
2267 wing_num = slot_index / 4;
2268 slot_num = slot_index % 4;
2270 // get the wing and slot entries
2271 wb = &Ss_wings[wing_num];
2272 ws = &wb->ss_slots[slot_num];
2275 ws->status &= ~(WING_SLOT_EMPTY | WING_SLOT_DISABLED);
2276 ws->status |= WING_SLOT_FILLED;
2279 void ss_blit_ship_icon(int x,int y,int ship_class,int bmap_num)
2281 // blit the bitmap in the correct location
2282 if(ship_class == -1){
2283 gr_set_bitmap(Wing_slot_empty_bitmap);
2285 ss_icon_info *icon = &Ss_icons[ship_class];
2286 Assert(icon->icon_bmaps[bmap_num] != -1);
2287 gr_set_bitmap(icon->icon_bmaps[bmap_num]);
2292 // ------------------------------------------------------------------------
2293 // unload_ship_icons() frees the memory that was used to hold the bitmaps
2296 void unload_wing_icons()
2298 if ( Wing_slot_empty_bitmap != -1 ) {
2299 bm_release(Wing_slot_empty_bitmap);
2300 Wing_slot_empty_bitmap = -1;
2303 if ( Wing_slot_disabled_bitmap != -1 ) {
2304 bm_release(Wing_slot_disabled_bitmap);
2305 Wing_slot_disabled_bitmap = -1;
2309 // ------------------------------------------------------------------------
2310 // create_wings() will ensure the correct ships are in the player wings
2311 // for the game. It works by calling change_ship_type() on the wing ships
2312 // so they match what the player selected. ship_create() is called for the
2313 // player ship (and current_count, ship_index[] is updated), since it is not yet
2314 // part of the wing structure.
2316 // returns: 0 ==> success
2325 int shipnum, objnum, slot_index;
2326 int cleanup_ship_index[MAX_WING_SLOTS];
2330 for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2334 if ( wb->wingnum == -1 )
2337 wp = &Wings[wb->wingnum];
2339 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2341 ws = &wb->ss_slots[j];
2342 switch ( ws->status ) {
2344 case WING_SLOT_FILLED:
2345 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2346 case WING_SLOT_FILLED|WING_SLOT_LOCKED:
2347 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER|WING_SLOT_LOCKED:
2348 if ( wp->ship_index[j] >= 0 ) {
2349 Assert(Ships[wp->ship_index[j]].objnum >= 0);
2352 if ( ws->status & WING_SLOT_IS_PLAYER ) {
2353 update_player_ship(Wss_slots[slot_index].ship_class);
2355 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[i*4+j]) == -1 ) {
2356 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
2360 objnum = OBJ_INDEX(Player_obj);
2361 shipnum = Objects[objnum].instance;
2365 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2366 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2367 if ( ws->sa_index == (p_objp-ship_arrivals) ) {
2368 p_objp->ship_class = Wss_slots[slot_index].ship_class;
2369 wl_update_parse_object_weapons(p_objp, &Wss_slots[i*4+j]);
2379 // Change the ship type of the ship if different than current.
2380 // NOTE: This will reset the weapons for this ship. I think this is
2381 // the right thing to do, since the ships may have different numbers
2382 // of weapons and may not have the same allowed weapon types
2383 if ( Ships[wp->ship_index[j]].ship_info_index != Wss_slots[slot_index].ship_class )
2384 change_ship_type(wp->ship_index[j], Wss_slots[slot_index].ship_class);
2385 wl_update_ship_weapons(Ships[wp->ship_index[j]].objnum, &Wss_slots[i*4+j]);
2391 case WING_SLOT_EMPTY:
2392 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2393 if ( ws->status & WING_SLOT_IS_PLAYER ) {
2394 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player %s must select a place in player wing", 462), Player->callsign);
2402 } // end for (wing slot)
2403 } // end for (wing block)
2405 for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2407 wp = &Wings[wb->wingnum];
2409 if ( wb->wingnum == -1 )
2412 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2413 cleanup_ship_index[k] = -1;
2416 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2417 ws = &wb->ss_slots[j];
2418 switch( ws->status ) {
2419 case WING_SLOT_EMPTY:
2420 // delete ship that is not going to be used by the wing
2421 if ( wb->is_late ) {
2422 list_remove( &ship_arrival_list, &ship_arrivals[ws->sa_index]);
2424 Assert(wp->wave_count >= 0);
2427 shipnum = wp->ship_index[j];
2428 Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
2429 cleanup_ship_index[j] = shipnum;
2430 ship_add_exited_ship( &Ships[shipnum], SEF_PLAYER_DELETED );
2431 obj_delete(Ships[shipnum].objnum);
2432 hud_set_wingman_status_none( Ships[shipnum].wing_status_wing_index, Ships[shipnum].wing_status_wing_pos);
2441 } // end for (wing slot)
2443 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2444 if ( cleanup_ship_index[k] != -1 ) {
2445 ship_wing_cleanup( cleanup_ship_index[k], wp );
2449 } // end for (wing block)
2454 void ship_stop_animation()
2456 if ( Ship_anim_class >= 0 )
2457 stop_ship_animation();
2460 // ----------------------------------------------------------------------------
2461 // update_player_ship()
2463 // Updates the ship class of the player ship
2465 // parameters: si_index => ship info index of ship class to change to
2468 void update_player_ship(int si_index)
2470 Assert( si_index >= 0 );
2471 Assert( Player_obj != NULL);
2474 // Change the ship type of the player ship if different than current.
2475 // NOTE: This will reset the weapons for this ship. I think this is
2476 // the right thing to do, since the ships may have different numbers
2477 // of weapons and may not have the same allowed weapon types
2478 if ( Player_ship->ship_info_index != si_index )
2479 change_ship_type(Player_obj->instance, si_index);
2481 Player->last_ship_flown_si_index = si_index;
2484 // ----------------------------------------------------------------------------
2485 // create a default player ship
2487 // parameters: use_last_flown => select ship that was last flown on a mission
2488 // (this is a default parameter which is set to 1)
2490 // returns: 0 => success
2493 int create_default_player_ship(int use_last_flown)
2495 int player_ship_class=-1, i;
2497 // find the ship that matches the string stored in default_player_ship
2499 if ( use_last_flown ) {
2500 player_ship_class = Players[Player_num].last_ship_flown_si_index;
2503 for (i = 0; i < Num_ship_types; i++) {
2504 if ( !stricmp(Ship_info[i].name, default_player_ship) ) {
2505 player_ship_class = i;
2506 Players[Player_num].last_ship_flown_si_index = player_ship_class;
2511 if (i == Num_ship_types)
2515 update_player_ship(player_ship_class);
2517 // debug code to keep using descent style physics if the player starts a new game
2519 if ( use_descent ) {
2521 toggle_player_object();
2528 // return the original ship class for the specified slot
2529 int ss_return_original_ship_class(int slot_num)
2536 return Ss_wings[wnum].ss_slots[snum].original_ship_class;
2539 // return the ship arrival index for the slot (-1 means no ship arrival index)
2540 int ss_return_saindex(int slot_num)
2547 return Ss_wings[wnum].ss_slots[snum].sa_index;
2550 // ----------------------------------------------------------------------------
2553 // For a given wing slot, return the ship index if the ship has been created.
2554 // Otherwise, find the index into ship_arrivals[] for the ship
2556 // input: wing_block => wing block of ship to find
2557 // wing_slot => wing slot of ship to find
2558 // ship_index => OUTPUT parameter: the Ships[] index of the ship in the wing slot
2559 // This value will be -1 if there is no ship created yet
2560 // ppobjp => OUTPUT parameter: returns a pointer to a parse object for
2561 // the ship that hasn't been created yet. Set to NULL if the
2562 // ship has already been created
2564 // returns: the original ship class of the ship, or -1 if the ship doesn't exist
2566 // NOTE: For the player wing, the player is not yet in the wp->ship_index[].. so
2567 // that is why there is an offset of 1 when getting ship indicies from the player
2568 // wing. The player is special cased by looking at the status of the wing slot
2570 int ss_return_ship(int wing_block, int wing_slot, int *ship_index, p_object **ppobjp)
2577 if (!Wss_num_wings) {
2579 *ship_index = Player_obj->instance;
2580 return Player_ship->ship_info_index;
2583 if ( Ss_wings[wing_block].wingnum < 0 ) {
2587 ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2589 // Check to see if ship is on the ship_arrivals[] list
2590 if ( ws->sa_index != -1 ) {
2592 *ppobjp = &ship_arrivals[ws->sa_index];
2594 *ship_index = Wings[Ss_wings[wing_block].wingnum].ship_index[wing_slot];
2595 Assert(*ship_index != -1);
2598 return ws->original_ship_class;
2601 // return the name of the ship in the specified wing position... if the ship is the
2602 // player ship, return the player callsign
2604 // input: ensure at least NAME_LENGTH bytes allocated for name buffer
2605 void ss_return_name(int wing_block, int wing_slot, char *name)
2610 ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2611 wp = &Wings[Ss_wings[wing_block].wingnum];
2613 if (!Wss_num_wings) {
2614 strcpy(name, Player->callsign);
2618 // Check to see if ship is on the ship_arrivals[] list
2619 if ( ws->sa_index != -1 ) {
2620 strcpy(name, ship_arrivals[ws->sa_index].name);
2623 sp = &Ships[wp->ship_index[wing_slot]];
2625 // in multiplayer, return the callsigns of the players who are in the ships
2626 if(Game_mode & GM_MULTIPLAYER){
2627 int player_index = multi_find_player_by_object(&Objects[sp->objnum]);
2628 if(player_index != -1){
2629 strcpy(name,Net_players[player_index].player->callsign);
2631 strcpy(name,sp->ship_name);
2634 strcpy(name, sp->ship_name);
2639 int ss_get_selected_ship()
2641 return Selected_ss_class;
2644 // Set selected ship to the first occupied wing slot, or first ship in pool if no slots are occupied
2645 void ss_reset_selected_ship()
2649 Selected_ss_class = -1;
2651 if ( Wss_num_wings <= 0 ) {
2652 Selected_ss_class = Team_data[Common_team].default_ship;
2656 // get first ship class found on slots
2657 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2658 if ( Wss_slots[i].ship_class >= 0 ) {
2659 Selected_ss_class = Wss_slots[i].ship_class;
2664 if ( Selected_ss_class == -1 ) {
2666 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2667 if ( Ss_pool[i] > 0 ) {
2668 Selected_ss_class = i;
2673 if ( Selected_ss_class == -1 ) {
2679 // There may be ships that are in wings but not in Team_data[0]. Since we still want to show those
2680 // icons in the ship selection list, the code below checks for these cases. If a ship is found in
2681 // a wing, and is not in Team_data[0], it is appended to the end of the ship_count[] and ship_list[] arrays
2682 // that are in Team_data[0]
2684 // exit: number of distinct ship classes available to choose from
2685 int ss_fixup_team_data(team_data *tdata)
2687 int i, j, k, ship_in_parse_player, list_size;
2689 team_data *p_team_data;
2691 p_team_data = tdata;
2692 ship_in_parse_player = 0;
2693 list_size = p_team_data->number_choices;
2695 for ( i = 0; i < MAX_PLAYER_WINGS; i++ ) {
2697 if ( Starting_wings[i] == -1 )
2699 wp = &Wings[Starting_wings[i]];
2700 for ( j = 0; j < wp->current_count; j++ ) {
2701 ship_in_parse_player = 0;
2703 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2704 Assert( p_team_data->ship_count[k] >= 0 );
2705 if ( p_team_data->ship_list[k] == Ships[wp->ship_index[j]].ship_info_index ) {
2706 ship_in_parse_player = 1;
2709 } // end for, go to next item in parse player
2711 if ( !ship_in_parse_player ) {
2712 p_team_data->ship_count[list_size] = 0;
2713 p_team_data->ship_list[list_size] = Ships[wp->ship_index[j]].ship_info_index;
2714 p_team_data->number_choices++;
2717 } // end for, go get next ship in wing
2719 if ( wp->current_count == 0 ) {
2721 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2722 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2723 ship_in_parse_player = 0;
2725 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2726 Assert( p_team_data->ship_count[k] >= 0 );
2727 if ( p_team_data->ship_list[k] == p_objp->ship_class ) {
2728 ship_in_parse_player = 1;
2731 } // end for, go to next item in parse player
2733 if ( !ship_in_parse_player ) {
2734 p_team_data->ship_count[list_size] = 0;
2735 p_team_data->ship_list[list_size] = p_objp->ship_class;
2736 p_team_data->number_choices++;
2742 } // end for, go to next wing
2744 if ( list_size == 0 ) {
2745 // ensure that the default player ship is in the ship_list too
2746 ship_in_parse_player = 0;
2747 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2748 Assert( p_team_data->ship_count[k] >= 0 );
2749 if ( p_team_data->ship_list[k] == p_team_data->default_ship ) {
2750 ship_in_parse_player = 1;
2754 if ( !ship_in_parse_player ) {
2755 p_team_data->ship_count[list_size] = 0;
2756 p_team_data->ship_list[list_size] = p_team_data->default_ship;
2757 p_team_data->number_choices++;
2765 // set numbers of ships in pool to default values
2766 void ss_init_pool(team_data *pteam)
2770 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2774 // set number of available ships based on counts in team_data
2775 for ( i = 0; i < pteam->number_choices; i++ ) {
2776 Ss_pool[pteam->ship_list[i]] = pteam->ship_count[i];
2780 // load the icons for a specific ship class
2781 void ss_load_icons(int ship_class)
2784 int first_frame, num_frames, i;
2786 icon = &Ss_icons[ship_class];
2788 first_frame = bm_load_animation(Ship_info[ship_class].icon_filename, &num_frames);
2789 if ( first_frame == -1 ) {
2790 Int3(); // Could not load in icon frames.. get Alan
2794 for ( i = 0; i < num_frames; i++ ) {
2795 icon->icon_bmaps[i] = first_frame+i;
2798 // set the current bitmap for the ship icon
2799 icon->current_icon_bitmap = icon->icon_bmaps[ICON_FRAME_NORMAL];
2802 // load all the icons for ships in the pool
2803 void ss_load_all_icons()
2805 #ifndef DEMO // not for FS2_DEMO
2809 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2811 Ss_icons[i].current_icon_bitmap = -1;
2812 Ss_icons[i].anim = NULL;
2813 Ss_icons[i].anim_instance = NULL;
2814 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
2815 Ss_icons[i].icon_bmaps[j] = -1;
2818 if ( Ss_pool[i] >= 0 ) {
2826 // Load in a specific ship animation. The data is loaded as a memory-mapped file since these animations
2828 void ss_load_anim(int ship_class)
2832 icon = &Ss_icons[ship_class];
2834 // load the compressed ship animation into memory
2835 // NOTE: if last parm of load_anim is 1, the anim file is mapped to memory
2836 Assert( icon->anim == NULL );
2837 icon->anim = ss_load_individual_animation(ship_class);
2838 if ( icon->anim == NULL ) {
2839 Int3(); // couldn't load anim filename.. get Alan
2843 // Load in any ship animations. This function assumes that Ss_pool has been inited.
2844 void ss_load_all_anims()
2846 #ifndef DEMO // not for FS2_DEMO
2850 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2851 if ( Ss_pool[i] > 0 ) {
2859 // determine if the slot is disabled
2860 int ss_disabled_slot(int slot_num)
2862 if ( Wss_num_wings <= 0 ){
2866 // HACK HACK HACK - call the team select function in multiplayer
2867 if(Game_mode & GM_MULTIPLAYER) {
2868 return multi_ts_disabled_slot(slot_num);
2870 return ( Ss_wings[slot_num/4].ss_slots[slot_num%4].status & WING_SLOT_IGNORE );
2873 // reset the slot data
2874 void ss_clear_slots()
2879 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2880 Wss_slots[i].ship_class = -1;
2883 for ( i = 0; i < 3; i++ ) {
2884 for ( j = 0; j < 4; j++ ) {
2885 slot = &Ss_wings[i].ss_slots[j];
2886 slot->status = WING_SLOT_DISABLED;
2887 slot->sa_index = -1;
2888 slot->original_ship_class = -1;
2893 // initialize all wing struct stuff
2894 void ss_clear_wings()
2898 for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
2899 Ss_wings[idx].wingnum = -1;
2900 Ss_wings[idx].num_slots = 0;
2901 Ss_wings[idx].is_late = 0;
2905 // set up Wss_num_wings and Wss_wings[] based on Starting_wings[] info
2906 void ss_init_wing_info(int wing_num,int starting_wing_num)
2909 ss_wing_info *ss_wing;
2912 ss_wing = &Ss_wings[wing_num];
2914 if ( Starting_wings[starting_wing_num] < 0 ) {
2918 ss_wing->wingnum = Starting_wings[starting_wing_num];
2921 wp = &Wings[Ss_wings[wing_num].wingnum];
2922 ss_wing->num_slots = wp->current_count;
2924 if ( wp->current_count == 0 || wp->ship_index[0] == -1 ) {
2926 // Temporarily fill in the current count and initialize the ship list in the wing
2927 // This gets cleaned up before the mission is started
2928 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2929 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2930 slot = &ss_wing->ss_slots[ss_wing->num_slots++];
2931 slot->sa_index = p_objp-ship_arrivals;
2932 slot->original_ship_class = p_objp->ship_class;
2934 ss_wing->is_late = 1;
2939 // Determine if a ship is actually a console player ship
2940 int ss_wing_slot_is_console_player(int index)
2942 int wingnum, slotnum;
2947 if ( wingnum >= Wss_num_wings ) {
2951 if ( Ss_wings[wingnum].ss_slots[slotnum].status & WING_SLOT_IS_PLAYER ) {
2958 // init the ship selection portion of the units, and set up the ui data
2959 void ss_init_units()
2963 ss_slot_info *ss_slot;
2964 ss_wing_info *ss_wing;
2966 for ( i = 0; i < Wss_num_wings; i++ ) {
2968 ss_wing = &Ss_wings[i];
2970 if ( ss_wing->wingnum < 0 ) {
2975 wp = &Wings[ss_wing->wingnum];
2977 for ( j = 0; j < ss_wing->num_slots; j++ ) {
2979 ss_slot = &ss_wing->ss_slots[j];
2981 if ( ss_slot->sa_index == -1 ) {
2982 ss_slot->original_ship_class = Ships[wp->ship_index[j]].ship_info_index;
2985 // Set the type of slot. Check if the slot is marked as locked, if so then the player is not
2986 // going to be able to modify that ship.
2987 if ( ss_slot->sa_index == -1 ) {
2989 if ( Ships[wp->ship_index[j]].flags & SF_LOCKED ) {
2990 ss_slot->status = WING_SLOT_DISABLED;
2991 ss_slot->status |= WING_SLOT_LOCKED;
2993 ss_slot->status = WING_SLOT_FILLED;
2996 objnum = Ships[wp->ship_index[j]].objnum;
2997 if ( Objects[objnum].flags & OF_PLAYER_SHIP ) {
2998 if ( ss_slot->status & WING_SLOT_LOCKED ) {
2999 // Int3(); // Get Alan
3002 ss_slot->status &= ~(WING_SLOT_LOCKED);
3004 ss_slot->status = WING_SLOT_FILLED;
3005 if ( objnum == OBJ_INDEX(Player_obj) ) {
3006 ss_slot->status |= WING_SLOT_IS_PLAYER;
3010 if ( ship_arrivals[ss_slot->sa_index].flags & P_SF_LOCKED ) {
3011 ss_slot->status = WING_SLOT_DISABLED;
3012 ss_slot->status |= WING_SLOT_LOCKED;
3014 ss_slot->status = WING_SLOT_FILLED;
3016 if ( ship_arrivals[ss_slot->sa_index].flags & P_OF_PLAYER_START ) {
3017 if ( ss_slot->status & WING_SLOT_LOCKED ) {
3018 // Int3(); // Get Alan
3021 ss_slot->status &= ~(WING_SLOT_LOCKED);
3023 ss_slot->status = WING_SLOT_FILLED;
3024 ss_slot->status |= WING_SLOT_IS_PLAYER;
3028 // Assign the ship class to the unit
3029 Wss_slots[i*4+j].ship_class = ss_slot->original_ship_class;
3034 // lock/unlock any necessary slots for multiplayer
3035 if(Game_mode & GM_MULTIPLAYER){
3036 ss_recalc_multiplayer_slots();
3040 // set the necessary pointers
3041 void ss_set_team_pointers(int team)
3043 Ss_wings = Ss_wings_teams[team];
3044 Ss_icons = Ss_icons_teams[team];
3045 Ss_pool = Ss_pool_teams[team];
3046 Wl_pool = Wl_pool_teams[team];
3047 Wss_slots = Wss_slots_teams[team];
3050 // initialize team specific stuff
3051 void ship_select_init_team_data(int team_num)
3055 // set up the pointers to initialize the data structures.
3056 Ss_wings = Ss_wings_teams[team_num];
3057 Ss_icons = Ss_icons_teams[team_num];
3058 Ss_pool = Ss_pool_teams[team_num];
3059 Wl_pool = Wl_pool_teams[team_num];
3060 Wss_slots = Wss_slots_teams[team_num];
3062 ss_fixup_team_data(&Team_data[team_num]);
3063 ss_init_pool(&Team_data[team_num]);
3065 ss_clear_slots(); // reset data for slots
3068 // determine how many wings we should be checking for
3070 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3071 // now setup wings for easy reference
3072 ss_init_wing_info(0,team_num);
3074 // now setup wings for easy reference
3075 for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
3076 ss_init_wing_info(idx,idx);
3081 // if there are no wings, don't call the init_units() function
3082 if ( Wss_num_wings <= 0 ) {
3083 Wss_slots[0].ship_class = Team_data[team_num].default_ship;
3090 // called when the briefing is entered
3091 void ship_select_common_init()
3095 // initialize team critical data for all teams
3096 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3097 // initialize for all teams in the game
3098 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
3099 ship_select_init_team_data(idx);
3102 // finally, intialize team data for myself
3103 ship_select_init_team_data(Common_team);
3105 ship_select_init_team_data(Common_team);
3110 // load the necessary icons/animations
3111 ss_load_all_icons();
3112 ss_load_all_anims();
3114 ss_reset_selected_ship();
3115 ss_reset_carried_icon();
3118 // change any interface data based on updated Wss_slots[] and Ss_pool[]
3119 void ss_synch_interface()
3124 int old_list_start = SS_active_list_start;
3126 init_active_list(); // build the list of pool ships
3128 if ( old_list_start < SS_active_list_size ) {
3129 SS_active_list_start = old_list_start;
3132 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
3133 slot = &Ss_wings[i/4].ss_slots[i%4];
3135 if ( Wss_slots[i].ship_class == -1 ) {
3136 if ( slot->status & WING_SLOT_FILLED ) {
3137 slot->status &= ~WING_SLOT_FILLED;
3138 slot->status |= WING_SLOT_EMPTY;
3141 if ( slot->status & WING_SLOT_EMPTY ) {
3142 slot->status &= ~WING_SLOT_EMPTY;
3143 slot->status |= WING_SLOT_FILLED;
3149 // exit: data changed flag
3150 int ss_swap_slot_slot(int from_slot, int to_slot, int *sound)
3152 int i, tmp, fwnum, fsnum, twnum, tsnum;
3154 if ( from_slot == to_slot ) {
3155 *sound=SND_ICON_DROP_ON_WING;
3159 // ensure from_slot has a ship to pick up
3160 if ( Wss_slots[from_slot].ship_class < 0 ) {
3161 *sound=SND_ICON_DROP;
3165 fwnum = from_slot/4;
3166 fsnum = from_slot%4;
3172 tmp = Wss_slots[from_slot].ship_class;
3173 Wss_slots[from_slot].ship_class = Wss_slots[to_slot].ship_class;
3174 Wss_slots[to_slot].ship_class = tmp;
3177 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3178 tmp = Wss_slots[from_slot].wep[i];
3179 Wss_slots[from_slot].wep[i] = Wss_slots[to_slot].wep[i];
3180 Wss_slots[to_slot].wep[i] = tmp;
3182 tmp = Wss_slots[from_slot].wep_count[i];
3183 Wss_slots[from_slot].wep_count[i] = Wss_slots[to_slot].wep_count[i];
3184 Wss_slots[to_slot].wep_count[i] = tmp;
3187 *sound=SND_ICON_DROP_ON_WING;
3191 // exit: data changed flag
3192 int ss_dump_to_list(int from_slot, int to_list, int *sound)
3194 int i, fwnum, fsnum;
3197 slot = &Wss_slots[from_slot];
3199 // ensure from_slot has a ship to pick up
3200 if ( slot->ship_class < 0 ) {
3201 *sound=SND_ICON_DROP;
3205 fwnum = from_slot/4;
3206 fsnum = from_slot%4;
3208 // put ship back in list
3209 Ss_pool[to_list]++; // return to list
3210 slot->ship_class = -1; // remove from slot
3212 // put weapons back in list
3213 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3214 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3215 Wl_pool[slot->wep[i]] += slot->wep_count[i];
3217 slot->wep_count[i] = 0;
3221 *sound=SND_ICON_DROP;
3225 // exit: data changed flag
3226 int ss_grab_from_list(int from_list, int to_slot, int *sound)
3229 int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3231 slot = &Wss_slots[to_slot];
3233 // ensure that pool has ship
3234 if ( Ss_pool[from_list] <= 0 ) {
3235 *sound=SND_ICON_DROP;
3239 Assert(slot->ship_class < 0 ); // slot should be empty
3241 // take ship from list->slot
3242 Ss_pool[from_list]--;
3243 slot->ship_class = from_list;
3245 // take weapons from list->slot
3246 wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3247 wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3248 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3249 slot->wep[i] = wep[i];
3250 slot->wep_count[i] = wep_count[i];
3253 *sound=SND_ICON_DROP_ON_WING;
3257 // exit: data changed flag
3258 int ss_swap_list_slot(int from_list, int to_slot, int *sound)
3260 int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3263 // ensure that pool has ship
3264 if ( Ss_pool[from_list] <= 0 ) {
3265 *sound=SND_ICON_DROP;
3269 slot = &Wss_slots[to_slot];
3270 Assert(slot->ship_class >= 0 ); // slot should be filled
3272 // put ship from slot->list
3273 Ss_pool[Wss_slots[to_slot].ship_class]++;
3275 // put weapons from slot->list
3276 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3277 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3278 Wl_pool[slot->wep[i]] += slot->wep_count[i];
3280 slot->wep_count[i] = 0;
3284 // take ship from list->slot
3285 Ss_pool[from_list]--;
3286 slot->ship_class = from_list;
3288 // take weapons from list->slot
3289 wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3290 wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3291 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3292 slot->wep[i] = wep[i];
3293 slot->wep_count[i] = wep_count[i];
3296 *sound=SND_ICON_DROP_ON_WING;
3300 void ss_apply(int mode, int from_slot, int from_list, int to_slot, int to_list,int player_index)
3306 case WSS_SWAP_SLOT_SLOT:
3307 update = ss_swap_slot_slot(from_slot, to_slot, &sound);
3309 case WSS_DUMP_TO_LIST:
3310 update = ss_dump_to_list(from_slot, to_list, &sound);
3312 case WSS_GRAB_FROM_LIST:
3313 update = ss_grab_from_list(from_list, to_slot, &sound);
3315 case WSS_SWAP_LIST_SLOT:
3316 update = ss_swap_list_slot(from_list, to_slot, &sound);
3320 // only play this sound if the move was done locally (by the host in other words)
3321 if ( (sound >= 0) && (player_index == -1) ) {
3322 gamesnd_play_iface(sound);
3326 // NO LONGER USED - THERE IS A MULTIPLAYER VERSION OF THIS SCREEN NOW
3328 if ( MULTIPLAYER_HOST ) {
3330 ubyte wss_data[MAX_PACKET_SIZE-20];
3331 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound);
3332 send_wss_update_packet(wss_data, size, player_index);
3336 ss_synch_interface();
3340 void ss_drop(int from_slot,int from_list,int to_slot,int to_list,int player_index)
3343 common_flash_button_init();
3345 mode = wss_get_mode(from_slot, from_list, to_slot, to_list, -1);
3347 ss_apply(mode, from_slot, from_list, to_slot, to_list,player_index);
3351 // lock/unlock any necessary slots for multiplayer
3352 void ss_recalc_multiplayer_slots()
3356 ss_slot_info *ss_slot;
3357 ss_wing_info *ss_wing;
3360 if ( Wss_num_wings <= 0 ) {
3361 Wss_slots[0].ship_class = Team_data[Common_team].default_ship;;
3365 for ( i = 0; i < Wss_num_wings; i++ ) {
3366 ss_wing = &Ss_wings[i];
3367 if ( ss_wing->wingnum < 0 ) {
3372 // NOTE : the method below will eventually have to change to account for all possible netgame options
3374 // get the wing pointer
3375 wp = &Wings[ss_wing->wingnum];
3376 for ( j = 0; j < ss_wing->num_slots; j++ ) {
3377 // get the objnum of the ship in this slot
3378 objnum = Ships[wp->ship_index[j]].objnum;
3380 // get the slot pointer
3381 ss_slot = &ss_wing->ss_slots[j];
3383 if (ss_slot->sa_index == -1) {
3384 // lock all slots by default
3385 ss_slot->status |= WING_SLOT_LOCKED;
3387 // if this is my slot, then unlock it
3388 if(!multi_ts_disabled_slot((i*4)+j)){
3389 ss_slot->status &= ~WING_SLOT_LOCKED;