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.6 2005/03/29 02:18:47 taylor
19 * Various 64-bit platform fixes
20 * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
21 * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
22 * Streaming audio support (big thanks to Pierre Willenbrock!!)
23 * Removed dependance on strings.tbl for FS1 since we don't actually need it now
25 * Revision 1.5 2004/09/20 01:31:44 theoddone33
28 * Revision 1.4 2003/05/25 02:30:43 taylor
31 * Revision 1.3 2002/06/17 06:33:09 relnev
32 * ryan's struct patch for gcc 2.95
34 * Revision 1.2 2002/06/09 04:41:23 relnev
35 * added copyright header
37 * Revision 1.1.1.1 2002/05/03 03:28:10 root
41 * 26 11/02/99 3:23p Jefff
42 * "x Meters" to "x Meter" in German
44 * 25 8/05/99 3:40p Jefff
45 * hi-res text adjustments
47 * 24 8/04/99 11:56a Jefff
48 * fixed gamma wing hi-res coordinate error. fixed
49 * ss_load_individual_animation to load anis from a packfile.
51 * 23 7/30/99 4:22p Andsager
52 * restored ship and weapon anim sounds for demo. Added sound for
53 * changing ship in weapon loadout screen.
55 * 22 7/28/99 12:23p Jefff
56 * updated hi-res wing icon coords
58 * 21 7/21/99 3:24p Andsager
59 * Modify demo to use 2 frame ship and weapon select anis and cut sounds
62 * 20 7/16/99 2:23p Anoop
65 * 19 7/16/99 1:49p Dave
66 * 8 bit aabitmaps. yay.
68 * 18 7/15/99 6:36p Jamesa
69 * Moved default ship name into the ships.tbl
71 * 17 7/15/99 9:20a Andsager
72 * FS2_DEMO initial checkin
74 * 16 6/29/99 7:39p Dave
75 * Lots of small bug fixes.
77 * 15 6/04/99 11:32a Dave
78 * Added reset text to ship select screen. Fixed minor xstr bug in ui
81 * 14 3/23/99 9:26p Neilk
82 * fixed various multiplayer lock button problems
84 * 13 3/23/99 11:55a Neilk
85 * new support for ship anis
87 * 14 3/15/99 6:27p Neilk
88 * Added hires support for the ship animations
90 * 13 3/15/99 11:18a Neilk
91 * Modified animation code so ship animations loop back to frame 51
93 * 12 3/12/99 12:02p Davidg
94 * Modified coordinates for low res ship animations for new artwork
96 * 11 3/10/99 6:21p Neilk
97 * Added new artwork for hires
99 * 10 2/21/99 6:01p Dave
100 * Fixed standalone WSS packets.
102 * 9 2/18/99 11:46a Neilk
103 * hires interface coord support
105 * 8 2/11/99 3:08p Dave
106 * PXO refresh button. Very preliminary squad war support.
108 * 7 2/01/99 5:55p Dave
109 * Removed the idea of explicit bitmaps for buttons. Fixed text
110 * highlighting for disabled gadgets.
112 * 6 1/29/99 4:17p Dave
113 * New interface screens.
115 * 5 12/18/98 1:13a Dave
116 * Rough 1024x768 support for Direct3D. Proper detection and usage through
119 * 4 11/30/98 1:07p Dave
120 * 16 bit conversion, first run.
122 * 3 10/13/98 9:28a Dave
123 * Started neatening up freespace.h. Many variables renamed and
124 * reorganized. Added AlphaColors.[h,cpp]
126 * 2 10/07/98 10:53a Dave
129 * 1 10/07/98 10:50a Dave
131 * 102 9/11/98 4:14p Dave
132 * Fixed file checksumming of < file_size. Put in more verbose kicking and
133 * PXO stats store reporting.
135 * 101 6/09/98 10:31a Hoffoss
136 * Created index numbers for all xstr() references. Any new xstr() stuff
137 * added from here on out should be added to the end if the list. The
138 * current list count can be found in FreeSpace.cpp (search for
141 * 100 6/01/98 11:43a John
142 * JAS & MK: Classified all strings for localization.
144 * 99 5/23/98 5:50p Lawrance
145 * Don't reset scroll offset when rebuilding the list
147 * 98 5/06/98 11:50p Lawrance
148 * Clean up help overlay code for loadout screens
150 * 97 4/30/98 6:03p Lawrance
151 * Make drag and drop work better.
153 * 96 4/29/98 3:31p Lawrance
154 * draw disabled frames for icons when appropriate
156 * 95 4/28/98 9:35a Dave
157 * Remove bogus assert in create_wings() for ships which arrive late and
158 * haven't been created yet.
160 * 94 4/27/98 6:02p Dave
161 * Modify how missile scoring works. Fixed a team select ui bug. Speed up
162 * multi_lag system. Put in new main hall.
164 * 93 4/14/98 12:57a Dave
165 * Made weapon select screen show netplayer names above ships. Fixed pilot
166 * info popup to show the status of pilot images more correctly.
168 * 92 4/13/98 3:27p Lawrance
169 * fix coords for ship selection pool numbers
171 * 91 4/13/98 3:11p Andsager
172 * Fixed bug when there is no description for a ship.
174 * 90 4/10/98 4:51p Hoffoss
175 * Made several changes related to tooltips.
177 * 89 4/05/98 7:43p Lawrance
178 * fix up saving/restoring of link status and auto-target/match-speed.
180 * 88 4/03/98 4:16p Adam
181 * changed coord's and skip frame for new SS animations
183 * 87 4/02/98 11:40a Lawrance
184 * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
186 * 86 4/01/98 11:19p Dave
187 * Put in auto-loading of xferred pilot pic files. Grey out background
188 * behind pinfo popup. Put a chatbox message in when players are kicked.
189 * Moved mission title down in briefing. Other ui fixes.
191 * 85 4/01/98 9:21p John
192 * Made NDEBUG, optimized build with no warnings or errors.
194 * 84 3/31/98 11:47p Lawrance
195 * Fix some bugs related to wingmen selection when doing a quick mission
198 * 83 3/31/98 1:50p Duncan
199 * ALAN: fix bugs with selecting alternate weapons
201 * 82 3/30/98 12:18a Lawrance
202 * change some DEMO_RELEASE code to not compile code rather than return
205 * 81 3/29/98 12:55a Lawrance
206 * Get demo build working with limited set of data.
208 * 80 3/26/98 6:01p Dave
209 * Put in file checksumming routine in cfile. Made pilot pic xferring more
210 * robust. Cut header size of voice data packets in half. Put in
211 * restricted game host query system.
213 * 79 3/25/98 8:43p Hoffoss
214 * Changed anim_play() to not be so damn complex when you try and call it.
216 * 78 3/12/98 4:03p Lawrance
217 * don't press buttons when icon dropped on them
219 * 77 3/09/98 11:13a Lawrance
220 * Fix up drop sound effects used in loadout screens.
222 * 76 3/06/98 5:36p Dave
223 * Finished up first rev of team vs team. Probably needs to be debugged
226 * 75 3/05/98 6:48p Lawrance
227 * reposition commit_pressed() to ensure popup gets called after clear but
230 * 74 3/05/98 5:03p Dave
231 * More work on team vs. team support for multiplayer. Need to fix bugs in
234 * 73 3/05/98 12:38a Lawrance
235 * Fix bug with flashing buttons showing over help overlay
237 * 72 3/02/98 5:42p John
238 * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from
239 * afterburner. Made gr_set_clip work good with negative x &y. Made
240 * model_caching be on by default. Made each cached model have it's own
241 * bitmap id. Made asteroids not rotate when model_caching is on.
243 * 71 3/01/98 3:26p Dave
244 * Fixed a few team select bugs. Put in multiplayer intertface sounds.
245 * Corrected how ships are disabled/enabled in team select/weapon select
248 * 70 2/28/98 7:04p Lawrance
249 * Don't show reset button in multiplayer
251 * 69 2/26/98 8:21p Allender
252 * fix compiler warning
254 * 68 2/26/98 4:59p Allender
255 * groundwork for team vs team briefings. Moved weaponry pool into the
256 * Team_data structure. Added team field into the p_info structure.
257 * Allow for mutliple structures in the briefing code.
259 * 67 2/24/98 6:21p Lawrance
260 * Integrate new reset button into loadout screens
262 * 66 2/22/98 4:30p John
263 * More string externalization classification
265 * 65 2/22/98 4:17p John
266 * More string externalization classification... 190 left to go!
268 * 64 2/22/98 12:19p John
269 * Externalized some strings
271 * 63 2/19/98 6:26p Dave
272 * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
273 * initial support for player data uploading.
275 * 62 2/18/98 3:56p Dave
276 * Several bugs fixed for mp team select screen. Put in standalone packet
277 * routing for team select.
279 * 61 2/17/98 6:07p Dave
280 * Tore out old multiplayer team select screen, installed new one.
282 * 60 2/13/98 3:46p Dave
283 * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
286 * 59 2/12/98 2:38p Allender
287 * fix multiplayer primary/secondary weapon problems when ships are
288 * outfitted with less than max number
290 * 58 2/07/98 5:47p Lawrance
291 * reset flashing if a button gets highlighted
293 * 57 2/05/98 11:21p Lawrance
294 * When flashing buttons, use highlight frame
296 * 56 1/30/98 10:00a Allender
297 * made large ships able to attack other ships. Made goal code recognize
298 * when ships removed from wings during ship select
300 * 55 1/22/98 5:26p Dave
301 * Modified some pregame sequencing packets. Starting to repair broken
304 * 54 1/17/98 2:46a Dave
305 * Reworked multiplayer join/accept process. Ingame join still needs to be
308 * 53 1/15/98 4:11p Lawrance
309 * Add call to check if slot is player occupied.
311 * 52 1/13/98 4:47p Allender
312 * change default terran ship to reflect new ship class name
314 * 51 1/12/98 5:17p Dave
315 * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
316 * work through the standalone.
318 * 50 1/10/98 12:46a Lawrance
319 * Store last_modified time for mission into player loadout struct.
321 * 49 1/09/98 6:06p Dave
322 * Put in network sound support for multiplayer ship/weapon select
323 * screens. Made clients exit game correctly through warp effect. Fixed
324 * main hall menu help overlay bug.
326 * 48 1/08/98 11:38a Lawrance
329 * 47 1/08/98 11:36a Lawrance
330 * Get ship select and weapons loadout icon dropping sound effects working
331 * for single and multiplayer
333 * 46 1/02/98 9:10p Lawrance
334 * Big changes to how colors get set on the HUD.
336 * 45 12/29/97 4:21p Lawrance
337 * Flash buttons on briefing/ship select/weapons loadout when enough time
338 * has elapsed without activity.
340 * 44 12/29/97 9:42a Lawrance
341 * Ensure that WING_SLOT_IS_PLAYER gets set correctly in multiplayer.
343 * 43 12/24/97 8:54p Lawrance
344 * Integrating new popup code
346 * 42 12/24/97 1:19p Lawrance
347 * fix some bugs with the multiplayer ship/weapons loadout
349 * 41 12/23/97 5:25p Allender
350 * more fixes to multiplayer ship selection. Fixed strange reentrant
351 * problem with cf_callback when loading freespace data
353 * 40 12/23/97 11:59a Allender
354 * changes to ship/wespon selection for multplayer. added sounds to some
355 * interface screens. Update and modiied end-of-briefing packets -- yet
358 * 39 12/23/97 11:04a Lawrance
359 * fix bug in ss_swap_slot_slot()
361 * 38 12/23/97 10:57a Lawrance
362 * move player_set_weapon_prefs() to when commit is pressed in briefing
363 * (from entering gameplay)
365 * 37 12/23/97 10:54a Lawrance
366 * fix some bugs in multiplayer ship selection
368 * 36 12/22/97 6:18p Lawrance
369 * Get save/restore of player loadout working with new code
371 * 35 12/22/97 1:40a Lawrance
372 * Re-write ship select/weapons loadout to be multiplayer friendly
374 * 34 12/19/97 1:23p Dave
375 * Put in multiplayer groundwork for new weapon/ship select screens.
381 #include "missionscreencommon.h"
382 #include "missionshipchoice.h"
383 #include "missionparse.h"
384 #include "missionbrief.h"
385 #include "freespace.h"
386 #include "gamesequence.h"
395 #include "linklist.h"
401 #include "audiostr.h"
404 #include "snazzyui.h"
405 #include "animplay.h"
406 #include "packunpack.h"
407 #include "missionweaponchoice.h"
408 #include "contexthelp.h"
411 #include "missionhotkey.h"
413 #include "multimsgs.h"
414 #include "missionload.h"
415 #include "eventmusic.h"
419 #include "multiteamselect.h"
420 #include "multiutil.h"
421 #include "hudwingmanstatus.h"
422 #include "alphacolors.h"
423 #include "localize.h"
425 //////////////////////////////////////////////////////
427 //////////////////////////////////////////////////////
428 char default_player_ship[255] = NOX("GTF Ulysses");
429 int Select_default_ship = 0;
430 int Ship_select_open = 0; // This game-wide global flag is set to 1 to indicate that the ship
431 // select screen has been opened and memory allocated. This flag
432 // is needed so we can know if ship_select_close() needs to called if
433 // restoring a game from the Options screen invoked from ship select
435 int Commit_pressed; // flag to indicate that the commit button was pressed
436 // use a flag, so the ship_create() can be done at the end of the loop
438 //////////////////////////////////////////////////////
440 //////////////////////////////////////////////////////
441 static int Ship_anim_class = -1; // ship class that is playing as an animation
442 static int Ss_delta_x, Ss_delta_y; // used to offset the carried icon to make it smoothly leave static position
444 //////////////////////////////////////////////////////
446 //////////////////////////////////////////////////////
447 typedef struct ss_icon_info
449 int icon_bmaps[NUM_ICON_FRAMES];
450 int current_icon_bitmap;
452 anim_instance_t *anim_instance;
455 typedef struct ss_slot_info
457 int status; // slot status (WING_SLOT_DISABLED, etc)
458 int sa_index; // index into ship arrival list, -1 if ship is created
459 int original_ship_class;
462 typedef struct ss_wing_info
467 ss_slot_info ss_slots[MAX_WING_SLOTS];
470 //ss_icon_info Ss_icons[MAX_SHIP_TYPES]; // holds ui info on different ship icons
471 //ss_wing_info Ss_wings[MAX_WING_BLOCKS]; // holds ui info for wings and wing slots
473 ss_wing_info Ss_wings_teams[MAX_TEAMS][MAX_WING_BLOCKS];
474 ss_wing_info *Ss_wings;
476 ss_icon_info Ss_icons_teams[MAX_TEAMS][MAX_SHIP_TYPES];
477 ss_icon_info *Ss_icons;
479 int Ss_mouse_down_on_region = -1;
481 int Selected_ss_class; // set to ship class of selected ship, -1 if none selected
482 int Hot_ss_icon; // index that icon is over in list (0..4)
483 int Hot_ss_slot; // index for slot that mouse is over (0..11)
485 ////////////////////////////////////////////////////////////
487 ////////////////////////////////////////////////////////////
488 UI_WINDOW Ship_select_ui_window;
490 static int Ship_anim_coords[GR_NUM_RESOLUTIONS][2] = {
504 static int Ship_info_coords[GR_NUM_RESOLUTIONS][2] = {
514 // coordinate lookup indicies
515 #define SHIP_SELECT_X_COORD 0
516 #define SHIP_SELECT_Y_COORD 1
517 #define SHIP_SELECT_W_COORD 2
518 #define SHIP_SELECT_H_COORD 3
521 // NK: changed from 37 to 51 for new FS2 animations
522 #if defined(FS2_DEMO) || defined(FS1_DEMO)
523 #define SHIP_ANIM_LOOP_FRAME 0
525 #define SHIP_ANIM_LOOP_FRAME 36
527 #define SHIP_ANIM_LOOP_FRAME 51
530 #define MAX_ICONS_ON_SCREEN 4
532 // (x,y) pairs for ship icon and ship icon number
533 int Ship_list_coords[GR_NUM_RESOLUTIONS][MAX_ICONS_ON_SCREEN][4] = {
548 // Store the x locations for the icons in the wing formations
549 int Wing_icon_coords[GR_NUM_RESOLUTIONS][MAX_WSS_SLOTS][2] = {
584 //////////////////////////////////////////////////////
585 // Linked List of icons to show on ship selection list
586 //////////////////////////////////////////////////////
587 #define SS_ACTIVE_ITEM_USED (1<<0)
588 typedef struct ss_active_item
590 ss_active_item *prev, *next;
595 static ss_active_item SS_active_head;
596 static ss_active_item SS_active_items[MAX_WSS_SLOTS];
598 static int SS_active_list_start;
599 static int SS_active_list_size;
601 //////////////////////////////////////////////////////
602 // Background bitmaps data for ship_select
603 //////////////////////////////////////////////////////
604 static const char* Ship_select_background_fname[GR_NUM_RESOLUTIONS] = {
614 static const char* Ship_select_background_mask_fname[GR_NUM_RESOLUTIONS] = {
619 int Ship_select_background_bitmap;
621 //////////////////////////////////////////////////////
622 // Ship select specific buttons
623 //////////////////////////////////////////////////////
624 #define NUM_SS_BUTTONS 4
625 #define SS_BUTTON_SCROLL_UP 0
626 #define SS_BUTTON_SCROLL_DOWN 1
627 #define SS_BUTTON_RESET 2
628 #define SS_BUTTON_DUMMY 3 // needed to capture mouse for drag/drop icons
630 // convenient struct for handling all button controls
632 const char *filename;
636 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
638 ss_buttons(const 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) {}
641 static ss_buttons Ship_select_buttons[GR_NUM_RESOLUTIONS][NUM_SS_BUTTONS] = {
644 ss_buttons("ssb_08", 0, 301, -1, -1, 8, 0), // SCROLL UP
645 ss_buttons("ssb_09", 0, 453, -1, -1, 9, 0), // SCROLL DOWN
646 ss_buttons("ssb_39", 566, 317, -1, -1, 39, 0), // RESET
647 ss_buttons("ssb_39", 0, 0, -1, -1, 99, 0) // dummy for drag n' drop
649 ss_buttons("ssb_08", 5, 303, -1, -1, 8, 0), // SCROLL UP
650 ss_buttons("ssb_09", 5, 454, -1, -1, 9, 0), // SCROLL DOWN
651 ss_buttons("ssb_39", 571, 347, -1, -1, 39,0), // RESET
652 ss_buttons("ssb_39", 0, 0, -1, -1, 99,0) // dummy for drag n' drop
656 ss_buttons("2_ssb_08", 8, 485, -1, -1, 8, 0), // SCROLL UP
657 ss_buttons("2_ssb_09", 8, 727, -1, -1, 9, 0), // SCROLL DOWN
658 ss_buttons("2_ssb_39", 913, 556, -1, -1, 39,0), // RESET
659 ss_buttons("2_ssb_39", 0, 0, -1, -1, 99,0) // dummy for drag n' drop
665 #define SHIP_SELECT_NUM_TEXT 1
667 UI_XSTR Ship_select_text[GR_NUM_RESOLUTIONS][SHIP_SELECT_NUM_TEXT] = {
669 { "Reset", 1337, 580, 337, UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[0][SS_BUTTON_RESET].button }
672 { "Reset", 1337, 938, 546, UI_XSTR_COLOR_GREEN, -1, &Ship_select_buttons[1][SS_BUTTON_RESET].button }
677 // Mask bitmap pointer and Mask bitmap_id
678 static bitmap* ShipSelectMaskPtr; // bitmap pointer to the ship select mask bitmap
679 static ubyte* ShipSelectMaskData; // pointer to actual bitmap data
680 static int Shipselect_mask_w, Shipselect_mask_h;
681 static int ShipSelectMaskBitmap; // bitmap id of the ship select mask bitmap
683 static MENU_REGION Region[NUM_SHIP_SELECT_REGIONS];
684 static int Num_mask_regions;
686 //////////////////////////////////////////////////////
687 // Drag and Drop variables
688 //////////////////////////////////////////////////////
689 typedef struct ss_carry_icon_info
691 int from_slot; // slot index (0..11), -1 if carried from list
692 int ship_class; // ship class of carried icon
694 } ss_carry_icon_info;
696 ss_carry_icon_info Carried_ss_icon;
698 ////////////////////////////////////////////////////////////////////
699 // Internal function prototypes
700 ////////////////////////////////////////////////////////////////////
703 void draw_ship_icons();
704 void draw_ship_icon_with_number(int screen_offset, int ship_class);
705 void stop_ship_animation();
706 void start_ship_animation(int ship_class, int play_sound=0);
709 int pick_from_ship_list(int screen_offset, int ship_class);
710 void pick_from_wing(int wb_num, int ws_num);
713 void ship_select_button_do(int i);
714 void ship_select_common_init();
715 void ss_reset_selected_ship();
716 void ss_restore_loadout();
717 void maybe_change_selected_wing_ship(int wb_num, int ws_num);
720 void ss_init_pool(team_data *pteam);
724 void ss_unload_icons();
725 void ss_init_units();
726 void unload_ship_anim_instances();
727 void unload_ship_anims();
728 anim* ss_load_individual_animation(int ship_class);
730 // Carry icon functions
731 int ss_icon_being_carried();
732 void ss_reset_carried_icon();
733 void ss_set_carried_icon(int from_slot, int ship_class);
735 #define SHIP_DESC_X 445
736 #define SHIP_DESC_Y 273
738 const char *ss_tooltip_handler(const char *str)
740 if (Selected_ss_class < 0)
743 if (!SDL_strcasecmp(str, NOX("@ship_name"))) {
744 return Ship_info[Selected_ss_class].name;
746 } else if (!SDL_strcasecmp(str, NOX("@ship_type"))) {
747 return Ship_info[Selected_ss_class].type_str;
749 } else if (!SDL_strcasecmp(str, NOX("@ship_maneuverability"))) {
750 return Ship_info[Selected_ss_class].maneuverability_str;
752 } else if (!SDL_strcasecmp(str, NOX("@ship_armor"))) {
753 return Ship_info[Selected_ss_class].armor_str;
755 } else if (!SDL_strcasecmp(str, NOX("@ship_manufacturer"))) {
756 return Ship_info[Selected_ss_class].manufacturer_str;
758 } else if (!SDL_strcasecmp(str, NOX("@ship_desc"))) {
762 str = Ship_info[Selected_ss_class].desc;
766 gr_get_string_size(&w, &h, str);
767 x = SHIP_DESC_X - w / 2;
768 y = SHIP_DESC_Y - h / 2;
770 gr_set_color_fast(&Color_black);
771 gr_rect(x - 5, y - 5, w + 10, h + 10);
773 gr_set_color_fast(&Color_bright_white);
774 gr_string(x, y, str);
781 // Is an icon being carried?
782 int ss_icon_being_carried()
784 if ( Carried_ss_icon.ship_class >= 0 ) {
791 // Clear out carried icon info
792 void ss_reset_carried_icon()
794 Carried_ss_icon.from_slot = -1;
795 Carried_ss_icon.ship_class = -1;
798 // return !0 if carried icon has moved from where it was picked up
799 int ss_carried_icon_moved()
803 mouse_get_pos( &mx, &my );
804 if ( Carried_ss_icon.from_x != mx || Carried_ss_icon.from_y != my) {
811 // Set carried icon data
812 void ss_set_carried_icon(int from_slot, int ship_class)
814 Carried_ss_icon.from_slot = from_slot;
815 Carried_ss_icon.ship_class = ship_class;
817 // Set the mouse to captured
818 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.capture_mouse();
821 // clear all active list items, and reset the flags inside the SS_active_items[] array
822 void clear_active_list()
825 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
826 SS_active_items[i].flags = 0;
827 SS_active_items[i].ship_class = -1;
829 list_init(&SS_active_head);
831 SS_active_list_start = 0;
832 SS_active_list_size = 0;
835 // get a free element from SS_active_items[]
836 ss_active_item *get_free_active_list_node()
839 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
840 if ( SS_active_items[i].flags == 0 ) {
841 SS_active_items[i].flags |= SS_ACTIVE_ITEM_USED;
842 return &SS_active_items[i];
848 // add a ship into the active list
849 void active_list_add(int ship_class)
853 sai = get_free_active_list_node();
854 SDL_assert(sai != NULL);
855 sai->ship_class = ship_class;
856 list_append(&SS_active_head, sai);
859 // remove a ship from the active list
860 void active_list_remove(int ship_class)
862 ss_active_item *sai, *temp;
864 // next store players not assigned to wings
865 sai = GET_FIRST(&SS_active_head);
867 while(sai != END_OF_LIST(&SS_active_head)){
868 temp = GET_NEXT(sai);
869 if ( sai->ship_class == ship_class ) {
870 list_remove(&SS_active_head, sai);
877 // Build up the ship selection active list, which is a list of all ships that the player
879 void init_active_list()
886 // build the active list
887 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
888 if ( Ss_pool[i] > 0 ) {
889 sai = get_free_active_list_node();
892 list_append(&SS_active_head, sai);
893 SS_active_list_size++;
899 void ship_select_check_buttons()
904 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
905 b = &Ship_select_buttons[gr_screen.res][i];
906 if ( b->button.pressed() ) {
907 ship_select_button_do(b->hotspot);
912 // reset the ship selection to the mission defaults
913 void ss_reset_to_default()
915 if ( Game_mode & GM_MULTIPLAYER ) {
920 stop_ship_animation();
922 ss_init_pool(&Team_data[Common_team]);
925 ss_reset_selected_ship();
926 ss_reset_carried_icon();
929 wl_reset_to_defaults();
931 start_ship_animation(Selected_ss_class, 1);
934 // -------------------------------------------------------------------
935 // ship_select_redraw_pressed_buttons()
937 // Redraw any ship select buttons that are pressed down. This function is needed
938 // since we sometimes need to draw pressed buttons last to ensure the entire
939 // button gets drawn (and not overlapped by other buttons)
941 void ship_select_redraw_pressed_buttons()
946 common_redraw_pressed_buttons();
948 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
949 b = &Ship_select_buttons[gr_screen.res][i];
950 if ( b->button.pressed() ) {
951 b->button.draw_forced(2);
956 void ship_select_buttons_init()
961 for ( i = 0; i < NUM_SS_BUTTONS; i++ ) {
962 b = &Ship_select_buttons[gr_screen.res][i];
963 b->button.create( &Ship_select_ui_window, "", b->x, b->y, 60, 30, b->scrollable);
964 // set up callback for when a mouse first goes over a button
965 b->button.set_highlight_action( common_play_highlight_sound );
966 b->button.set_bmaps(b->filename);
967 b->button.link_hotspot(b->hotspot);
972 for(i=0; i<SHIP_SELECT_NUM_TEXT; i++){
973 Ship_select_ui_window.add_XSTR(&Ship_select_text[gr_screen.res][i]);
977 // We don't want to have the reset button appear in multiplayer
978 if ( Game_mode & GM_MULTIPLAYER ) {
979 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.disable();
980 Ship_select_buttons[gr_screen.res][SS_BUTTON_RESET].button.hide();
983 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.disable();
984 Ship_select_buttons[gr_screen.res][SS_BUTTON_DUMMY].button.hide();
987 // -------------------------------------------------------------------------------------
988 // ship_select_button_do() do the button action for the specified pressed button
990 void ship_select_button_do(int i)
992 if ( Background_playing )
996 case SHIP_SELECT_SHIP_SCROLL_UP:
997 if ( Current_screen != ON_SHIP_SELECT )
1000 if ( common_scroll_down_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
1001 gamesnd_play_iface(SND_SCROLL);
1003 gamesnd_play_iface(SND_GENERAL_FAIL);
1007 case SHIP_SELECT_SHIP_SCROLL_DOWN:
1008 if ( Current_screen != ON_SHIP_SELECT )
1011 if ( common_scroll_up_pressed(&SS_active_list_start, SS_active_list_size, MAX_ICONS_ON_SCREEN) ) {
1012 gamesnd_play_iface(SND_SCROLL);
1014 gamesnd_play_iface(SND_GENERAL_FAIL);
1019 case SHIP_SELECT_RESET:
1020 ss_reset_to_default();
1025 // ---------------------------------------------------------------------
1026 // ship_select_init() is called once when the ship select screen begins
1029 void ship_select_init()
1031 common_set_interface_palette("ShipPalette");
1032 common_flash_button_init();
1034 // if in multiplayer -- set my state to be ship select
1035 if ( Game_mode & GM_MULTIPLAYER ){
1036 // also set the ship which is mine as the default
1037 maybe_change_selected_wing_ship(Net_player->p_info.ship_index/4,Net_player->p_info.ship_index % 4);
1040 set_active_ui(&Ship_select_ui_window);
1041 Current_screen = ON_SHIP_SELECT;
1043 Ss_mouse_down_on_region = -1;
1045 help_overlay_set_state(SS_OVERLAY,0);
1047 if ( Ship_select_open ) {
1048 start_ship_animation( Selected_ss_class );
1049 common_buttons_maybe_reload(&Ship_select_ui_window); // AL 11-21-97: this is necessary since we may returning from the hotkey
1050 // screen, which can release common button bitmaps.
1051 common_reset_buttons();
1052 nprintf(("Alan","ship_select_init() returning without doing anything\n"));
1056 nprintf(("Alan","entering ship_select_init()\n"));
1057 common_select_init();
1059 ShipSelectMaskBitmap = bm_load(Ship_select_background_mask_fname[gr_screen.res]);
1060 if (ShipSelectMaskBitmap < 0) {
1061 if (gr_screen.res == GR_640) {
1062 Error(LOCATION,"Could not load in 'shipselect-m'!");
1063 } else if (gr_screen.res == GR_1024) {
1064 Error(LOCATION,"Could not load in '2_shipselect-m'!");
1068 Shipselect_mask_w = -1;
1069 Shipselect_mask_h = -1;
1071 // get a pointer to bitmap by using bm_lock()
1072 ShipSelectMaskPtr = bm_lock(ShipSelectMaskBitmap, 8, BMP_AABITMAP);
1073 ShipSelectMaskData = (ubyte*)ShipSelectMaskPtr->data;
1074 bm_get_info(ShipSelectMaskBitmap, &Shipselect_mask_w, &Shipselect_mask_h);
1076 help_overlay_load(SS_OVERLAY);
1078 // Set up the mask regions
1079 // initialize the different regions of the menu that will react when the mouse moves over it
1080 Num_mask_regions = 0;
1082 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_BRIEFING_REGION, 0);
1083 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_SS_REGION, 0);
1084 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_WEAPON_REGION, 0);
1085 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_COMMIT_REGION, 0);
1086 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_HELP_REGION, 0);
1087 snazzy_menu_add_region(&Region[Num_mask_regions++], "", COMMON_OPTIONS_REGION, 0);
1089 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_UP, 0);
1090 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_SHIP_SCROLL_DOWN, 0);
1092 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_0, 0);
1093 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_1, 0);
1094 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_2, 0);
1095 snazzy_menu_add_region(&Region[Num_mask_regions++], "", SHIP_SELECT_ICON_3, 0);
1097 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_0, 0);
1098 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_1, 0);
1099 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_2, 0);
1100 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_0_SHIP_3, 0);
1101 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_0, 0);
1102 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_1, 0);
1103 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_2, 0);
1104 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_1_SHIP_3, 0);
1105 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_0, 0);
1106 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_1, 0);
1107 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_2, 0);
1108 snazzy_menu_add_region(&Region[Num_mask_regions++], "", WING_2_SHIP_3, 0);
1110 Ship_select_open = 1; // This game-wide global flag is set to 1 to indicate that the ship
1111 // select screen has been opened and memory allocated. This flag
1112 // is needed so we can know if ship_select_close() needs to called if
1113 // restoring a game from the Options screen invoked from ship select
1115 // init ship selection masks and buttons
1116 Ship_select_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1117 Ship_select_ui_window.set_mask_bmap(Ship_select_background_mask_fname[gr_screen.res]);
1118 Ship_select_ui_window.tooltip_handler = ss_tooltip_handler;
1119 common_buttons_init(&Ship_select_ui_window);
1120 ship_select_buttons_init();
1121 start_ship_animation( Selected_ss_class );
1123 // init ship selection background bitmpa
1124 Ship_select_background_bitmap = bm_load(Ship_select_background_fname[gr_screen.res]);
1128 // Return the ship class for the icon specified by index. Need to iterate through the active
1129 // list of icons to find out what ship class for this icon
1131 // input: index => list index (0..3)
1132 // exit: ship class, -1 if none
1134 int ss_get_ship_class_from_list(int index)
1136 ss_active_item *sai;
1137 int list_entry, i, count;
1142 for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1144 if ( count <= SS_active_list_start )
1147 if ( i >= MAX_ICONS_ON_SCREEN )
1151 list_entry = sai->ship_class;
1161 // ---------------------------------------------------------------------
1162 // maybe_pick_up_list_icon()
1164 void maybe_pick_up_list_icon(int offset)
1168 ship_class = ss_get_ship_class_from_list(offset);
1169 if ( ship_class != -1 ) {
1170 pick_from_ship_list(offset, ship_class);
1174 // ---------------------------------------------------------------------
1175 // maybe_change_selected_ship()
1177 void maybe_change_selected_ship(int offset)
1181 ship_class = ss_get_ship_class_from_list(offset);
1182 if ( ship_class == -1 )
1185 if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+offset) ) {
1189 if ( Selected_ss_class == -1 ) {
1190 Selected_ss_class = ship_class;
1191 start_ship_animation(Selected_ss_class, 1);
1193 else if ( Selected_ss_class != ship_class ) {
1194 Selected_ss_class = ship_class;
1195 start_ship_animation(Selected_ss_class, 1);
1198 SDL_assert( Selected_ss_class == ship_class );
1201 void maybe_change_selected_wing_ship(int wb_num, int ws_num)
1203 ss_slot_info *ss_slot;
1205 SDL_assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
1206 SDL_assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS);
1208 if ( Ss_wings[wb_num].wingnum < 0 ) {
1212 ss_slot = &Ss_wings[wb_num].ss_slots[ws_num];
1213 switch ( ss_slot->status & ~WING_SLOT_LOCKED ) {
1215 case WING_SLOT_FILLED:
1216 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
1217 if ( Selected_ss_class != -1 && Selected_ss_class != Wss_slots[wb_num*4+ws_num].ship_class ) {
1218 Selected_ss_class = Wss_slots[wb_num*4+ws_num].ship_class;
1219 start_ship_animation(Selected_ss_class, 1);
1229 // ---------------------------------------------------------------------
1230 // do_mouse_over_wing_slot()
1232 // returns: 0 => icon wasn't dropped onto slot
1233 // 1 => icon was dropped onto slot
1234 int do_mouse_over_wing_slot(int block, int slot)
1236 Hot_ss_slot = block*4 + slot;
1238 if ( !mouse_down(MOUSE_LEFT_BUTTON) ) {
1239 if ( ss_icon_being_carried() ) {
1241 if ( ss_disabled_slot(block*4+slot) ) {
1242 gamesnd_play_iface(SND_ICON_DROP);
1246 if ( !ss_carried_icon_moved() ) {
1247 ss_reset_carried_icon();
1251 ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, Hot_ss_slot, -1);
1252 ss_reset_carried_icon();
1256 if ( Ss_mouse_down_on_region == (WING_0_SHIP_0+block*4+slot) ) {
1257 pick_from_wing(block, slot);
1264 void do_mouse_over_list_slot(int index)
1266 Hot_ss_icon = index;
1268 if ( Ss_mouse_down_on_region != (SHIP_SELECT_ICON_0+index) ){
1272 if ( mouse_down(MOUSE_LEFT_BUTTON) )
1273 maybe_pick_up_list_icon(index);
1276 // Icon has been dropped, but not onto a wing slot
1277 void ss_maybe_drop_icon()
1279 if ( Drop_icon_mflag ) {
1280 if ( ss_icon_being_carried() ) {
1281 // Add back into the ship entry list
1282 if ( Carried_ss_icon.from_slot >= 0 ) {
1284 ss_drop(Carried_ss_icon.from_slot, -1, -1, Carried_ss_icon.ship_class);
1286 if ( ss_carried_icon_moved() ) {
1287 gamesnd_play_iface(SND_ICON_DROP);
1290 ss_reset_carried_icon();
1295 void ss_anim_pause()
1297 if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1298 anim_pause(Ss_icons[Selected_ss_class].anim_instance);
1302 void ss_anim_unpause()
1304 if ( Selected_ss_class >= 0 && Ss_icons[Selected_ss_class].anim_instance ) {
1305 anim_unpause(Ss_icons[Selected_ss_class].anim_instance);
1309 // maybe flash a button if player hasn't done anything for a while
1310 void ss_maybe_flash_button()
1312 if ( common_flash_bright() ) {
1313 // weapon loadout button
1314 if ( Common_buttons[Current_screen-1][gr_screen.res][2].button.button_hilighted() ) {
1315 common_flash_button_init();
1317 Common_buttons[Current_screen-1][gr_screen.res][2].button.draw_forced(1);
1323 // -------------------------------------------------------------------------------------
1324 // ship_select_render(float frametime)
1326 void ship_select_render(float frametime)
1328 if ( !Background_playing ) {
1329 gr_set_bitmap(Ship_select_background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1333 anim_render_all(0, frametime);
1334 anim_render_all(ON_SHIP_SELECT, frametime);
1338 // blit any active ship information text
1339 void ship_select_blit_ship_info()
1345 color *header = &Color_white;
1346 color *text = &Color_green;
1349 // if we don't have a valid ship selected, do nothing
1350 if(Selected_ss_class == -1){
1354 // get the ship class
1355 sip = &Ship_info[Selected_ss_class];
1358 y_start = Ship_info_coords[gr_screen.res][SHIP_SELECT_Y_COORD];
1362 // blit the ship class (name)
1363 gr_set_color_fast(header);
1364 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Class",739));
1366 if(strlen(sip->name)){
1367 gr_set_color_fast(text);
1368 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->name);
1372 // blit the ship type
1373 gr_set_color_fast(header);
1374 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Type",740));
1376 if((sip->type_str != NULL) && strlen(sip->type_str)){
1377 gr_set_color_fast(text);
1378 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->type_str);
1382 // blit the ship length
1383 gr_set_color_fast(header);
1384 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Length",741));
1386 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1388 // in german, drop the s from Meters and make sure M is caps
1389 char *sp = strstr(sip->ship_length, "Meters");
1391 sp[5] = ' '; // make the old s a space now
1394 gr_set_color_fast(text);
1395 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start, sip->ship_length);
1399 // blit the max velocity
1400 gr_set_color_fast(header);
1401 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Max Velocity",742));
1403 SDL_snprintf(str,SDL_arraysize(str),XSTR("%d m/s",743),(int)sip->max_vel.xyz.z);
1404 gr_set_color_fast(text);
1405 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,str);
1408 // blit the maneuverability
1409 gr_set_color_fast(header);
1410 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Maneuverability",744));
1412 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1413 gr_set_color_fast(text);
1414 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->maneuverability_str);
1419 gr_set_color_fast(header);
1420 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Armor",745));
1422 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1423 gr_set_color_fast(text);
1424 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->armor_str);
1428 // blit the gun mounts
1429 gr_set_color_fast(header);
1430 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Gun Mounts",746));
1432 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1433 gr_set_color_fast(text);
1434 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->gun_mounts);
1438 // blit the missile banke
1439 gr_set_color_fast(header);
1440 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Missile Banks",747));
1442 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1443 gr_set_color_fast(text);
1444 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->missile_banks);
1448 // blit the manufacturer
1449 gr_set_color_fast(header);
1450 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start,XSTR("Manufacturer",748));
1452 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1453 gr_set_color_fast(text);
1454 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD]+4, y_start,sip->manufacturer_str);
1459 // blit the _short_ text description
1460 SDL_assert(Multi_ts_ship_info_line_count < 3);
1461 gr_set_color_fast(&Color_normal);
1462 for(idx=0;idx<SHIP_SELECT_ship_info_line_count;idx++){
1463 gr_string(Ship_info_coords[gr_screen.res][SHIP_SELECT_X_COORD], y_start, SHIP_SELECT_ship_info_lines[idx]);
1471 // ---------------------------------------------------------------------
1472 // ship_select_do() is called once per game frame, and is responsible for
1473 // updating the ship select screen
1475 // frametime is in seconds
1476 void ship_select_do(float frametime)
1478 int k, ship_select_choice, snazzy_action;
1480 ship_select_choice = snazzy_menu_do(ShipSelectMaskData, Shipselect_mask_w, Shipselect_mask_h, Num_mask_regions, Region, &snazzy_action, 0);
1485 k = common_select_do(frametime);
1487 if ( help_overlay_active(SS_OVERLAY) ) {
1494 // Check common keypresses
1495 common_check_keys(k);
1497 if ( Mouse_down_last_frame ) {
1498 Ss_mouse_down_on_region = ship_select_choice;
1501 // Check for the mouse over a region (not clicked, just over)
1502 if ( ship_select_choice > -1 ) {
1504 switch(ship_select_choice) {
1505 case SHIP_SELECT_ICON_0:
1506 do_mouse_over_list_slot(0);
1508 case SHIP_SELECT_ICON_1:
1509 do_mouse_over_list_slot(1);
1511 case SHIP_SELECT_ICON_2:
1512 do_mouse_over_list_slot(2);
1514 case SHIP_SELECT_ICON_3:
1515 do_mouse_over_list_slot(3);
1518 if ( do_mouse_over_wing_slot(0,0) )
1519 ship_select_choice = -1;
1522 if ( do_mouse_over_wing_slot(0,1) )
1523 ship_select_choice = -1;
1526 if ( do_mouse_over_wing_slot(0,2) )
1527 ship_select_choice = -1;
1530 if ( do_mouse_over_wing_slot(0,3) )
1531 ship_select_choice = -1;
1534 if ( do_mouse_over_wing_slot(1,0) )
1535 ship_select_choice = -1;
1538 if ( do_mouse_over_wing_slot(1,1) )
1539 ship_select_choice = -1;
1542 if ( do_mouse_over_wing_slot(1,2) )
1543 ship_select_choice = -1;
1546 if ( do_mouse_over_wing_slot(1,3) )
1547 ship_select_choice = -1;
1550 if ( do_mouse_over_wing_slot(2,0) )
1551 ship_select_choice = -1;
1554 if ( do_mouse_over_wing_slot(2,1) )
1555 ship_select_choice = -1;
1558 if ( do_mouse_over_wing_slot(2,2) )
1559 ship_select_choice = -1;
1562 if ( do_mouse_over_wing_slot(2,3) )
1563 ship_select_choice = -1;
1572 common_check_buttons();
1573 ship_select_check_buttons();
1575 // Check for the mouse clicks over a region
1576 if ( ship_select_choice > -1 && snazzy_action == SNAZZY_CLICKED ) {
1577 switch (ship_select_choice) {
1579 case SHIP_SELECT_ICON_0:
1580 maybe_change_selected_ship(0);
1583 case SHIP_SELECT_ICON_1:
1584 maybe_change_selected_ship(1);
1587 case SHIP_SELECT_ICON_2:
1588 maybe_change_selected_ship(2);
1591 case SHIP_SELECT_ICON_3:
1592 maybe_change_selected_ship(3);
1596 maybe_change_selected_wing_ship(0,0);
1600 maybe_change_selected_wing_ship(0,1);
1604 maybe_change_selected_wing_ship(0,2);
1608 maybe_change_selected_wing_ship(0,3);
1612 maybe_change_selected_wing_ship(1,0);
1616 maybe_change_selected_wing_ship(1,1);
1620 maybe_change_selected_wing_ship(1,2);
1624 maybe_change_selected_wing_ship(1,3);
1628 maybe_change_selected_wing_ship(2,0);
1632 maybe_change_selected_wing_ship(2,1);
1636 maybe_change_selected_wing_ship(2,2);
1640 maybe_change_selected_wing_ship(2,3);
1649 ss_maybe_drop_icon();
1651 if ( Ship_anim_class >= 0) {
1652 SDL_assert(Selected_ss_class >= 0);
1653 if ( Ss_icons[Selected_ss_class].anim_instance->frame_num == Ss_icons[Selected_ss_class].anim_instance->stop_at ) {
1654 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));
1655 anim_play_struct aps;
1656 anim_release_render_instance(Ss_icons[Selected_ss_class].anim_instance);
1657 anim_play_init(&aps, Ss_icons[Selected_ss_class].anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1658 aps.start_at = SHIP_ANIM_LOOP_FRAME;
1659 // aps.start_at = 0;
1660 aps.screen_id = ON_SHIP_SELECT;
1661 aps.framerate_independent = 1;
1662 aps.skip_frames = 0;
1663 Ss_icons[Selected_ss_class].anim_instance = anim_play(&aps);
1669 ship_select_render(frametime);
1670 if ( !Background_playing ) {
1671 Ship_select_ui_window.draw();
1672 ship_select_redraw_pressed_buttons();
1673 common_render_selected_screen_button();
1676 // The background transition plays once. Display ship icons after Background done playing
1677 if ( !Background_playing ) {
1679 for ( int i = 0; i < MAX_WING_BLOCKS; i++ ) {
1680 draw_wing_block(i, Hot_ss_slot, -1, Selected_ss_class);
1684 if ( ss_icon_being_carried() ) {
1685 int mouse_x, mouse_y;
1686 mouse_get_pos( &mouse_x, &mouse_y );
1687 gr_set_bitmap(Ss_icons[Carried_ss_icon.ship_class].icon_bmaps[ICON_FRAME_SELECTED], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1688 gr_bitmap(mouse_x + Ss_delta_x , mouse_y + Ss_delta_y);
1691 // draw out ship information
1692 ship_select_blit_ship_info();
1695 ss_maybe_flash_button();
1697 // blit help overlay if active
1698 help_overlay_maybe_blit(SS_OVERLAY);
1700 // If the commit button was pressed, do the commit button actions. Done at the end of the
1701 // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1702 // the ship model is not in memory
1703 if ( Commit_pressed ) {
1710 if ( Game_mode & GM_MULTIPLAYER ) {
1711 if ( Selected_ss_class >= 0 )
1712 Net_player->p_info.ship_class = Selected_ss_class;
1715 if(!Background_playing){
1716 // should render this as close to last as possible so it overlaps all controls
1717 // chatbox_render();
1720 // If the commit button was pressed, do the commit button actions. Done at the end of the
1721 // loop so there isn't a skip in the animation (since ship_create() can take a long time if
1722 // the ship model is not in memory
1723 if ( Commit_pressed ) {
1730 // ------------------------------------------------------------------------
1731 // ship_select_close() is called once when the ship select screen is exited
1734 void ship_select_close()
1738 if ( !Ship_select_open ) {
1739 nprintf(("Alan","ship_select_close() returning without doing anything\n"));
1743 nprintf(("Alan", "Entering ship_select_close()\n"));
1745 // done with the bitmaps, so unlock it
1746 bm_unlock(ShipSelectMaskBitmap);
1748 // unload the bitmaps
1749 bm_unload(ShipSelectMaskBitmap);
1750 help_overlay_unload(SS_OVERLAY);
1752 // release the bitmpas that were previously extracted from anim files
1755 // Release any active ship anim instances
1756 unload_ship_anim_instances();
1758 // unload ship animations if they were loaded
1759 unload_ship_anims();
1761 Ship_select_ui_window.destroy();
1764 common_free_interface_palette();
1767 Ship_anim_class = -1;
1768 Ship_select_open = 0; // This game-wide global flag is set to 0 to indicate that the ship
1769 // select screen has been closed and memory freed. This flag
1770 // is needed so we can know if ship_select_close() needs to called if
1771 // restoring a game from the Options screen invoked from ship select
1774 // ss_unload_icons() frees the bitmaps used for ship icons
1775 void ss_unload_icons()
1780 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
1781 icon = &Ss_icons[i];
1783 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
1784 if ( icon->icon_bmaps[j] >= 0 ) {
1785 bm_release(icon->icon_bmaps[j]);
1786 icon->icon_bmaps[j] = -1;
1792 // ------------------------------------------------------------------------
1793 // draw_ship_icons() will request which icons to draw on screen.
1794 void draw_ship_icons()
1799 ss_active_item *sai;
1801 for ( sai = GET_FIRST(&SS_active_head); sai != END_OF_LIST(&SS_active_head); sai = GET_NEXT(sai) ) {
1803 if ( count <= SS_active_list_start )
1806 if ( i >= MAX_ICONS_ON_SCREEN )
1809 draw_ship_icon_with_number(i, sai->ship_class);
1814 // ------------------------------------------------------------------------
1815 // draw_ship_icon_with_number() will draw a ship icon on screen with the
1816 // number of available ships to the left.
1819 void draw_ship_icon_with_number(int screen_offset, int ship_class)
1823 ss_icon_info *ss_icon;
1826 SDL_assert( screen_offset >= 0 && screen_offset <= 3 );
1827 SDL_assert( ship_class >= 0 );
1828 ss_icon = &Ss_icons[ship_class];
1830 num_x = Ship_list_coords[gr_screen.res][screen_offset][2];
1831 num_y = Ship_list_coords[gr_screen.res][screen_offset][3];
1833 // assume default bitmap is to be used
1834 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_NORMAL];
1836 // next check if ship has mouse over it
1837 if ( Hot_ss_icon > -1 ) {
1838 SDL_assert(Hot_ss_icon <= 3);
1839 if ( Hot_ss_icon == screen_offset )
1840 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_HOT];
1843 // highest precedence is if the ship is selected
1844 if ( Selected_ss_class > -1 ) {
1845 if ( Selected_ss_class == ship_class )
1846 ss_icon->current_icon_bitmap = ss_icon->icon_bmaps[ICON_FRAME_SELECTED];
1849 if ( Ss_pool[ship_class] <= 0 ) {
1854 gr_set_bitmap(ss_icon->current_icon_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1855 gr_bitmap(Ship_list_coords[gr_screen.res][screen_offset][0], Ship_list_coords[gr_screen.res][screen_offset][1]);
1858 SDL_snprintf(buf, SDL_arraysize(buf), "%d", Ss_pool[ship_class] );
1859 gr_set_color_fast(&Color_white);
1860 gr_string(num_x, num_y, buf);
1863 // ------------------------------------------------------------------------
1864 // stop_ship_animation() will halt the currently playing ship animation. The
1865 // instance will be freed, (but the compressed data is not freed). The animation
1866 // will not display after this function is called (even on this frame), since
1867 // the instance is removed from the anim_render_list.
1868 void stop_ship_animation()
1870 ss_icon_info *ss_icon;
1872 if ( Ship_anim_class == -1 )
1875 ss_icon = &Ss_icons[Ship_anim_class];
1877 anim_release_render_instance(ss_icon->anim_instance);
1878 ss_icon->anim_instance = NULL;
1880 Ship_anim_class = -1;
1884 // ------------------------------------------------------------------------
1885 // this loads an individual animation file
1886 // it attempts to load a hires version (ie, it attaches a "2_" in front of the
1887 // filename. if no hires version is available, it defaults to the lowres
1889 anim* ss_load_individual_animation(int ship_class)
1892 char animation_filename[CF_MAX_FILENAME_LENGTH+4];
1895 // If we are in 1024x768, we first want to append "2_" in front of the filename
1896 if (gr_screen.res == GR_1024) {
1897 SDL_assert(strlen(Ship_info[ship_class].anim_filename) <= 30);
1898 SDL_strlcpy(animation_filename, "2_", SDL_arraysize(animation_filename));
1899 SDL_strlcat(animation_filename, Ship_info[ship_class].anim_filename, SDL_arraysize(animation_filename));
1900 // now check if file exists
1901 // GRR must add a .ANI at the end for detection
1902 SDL_strlcat(animation_filename, ".ani", SDL_arraysize(animation_filename));
1904 p_anim = anim_load(animation_filename);
1905 if (p_anim == NULL) {
1906 // failed loading hi-res, revert to low res
1907 SDL_strlcpy(animation_filename, Ship_info[ship_class].anim_filename, SDL_arraysize(animation_filename));
1908 p_anim = anim_load(animation_filename);
1909 mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename));
1911 mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1914 // this is lame and doesnt work cuz cf_exist() doesnt search the packfiles
1915 if (!cf_exist(animation_filename, CF_TYPE_INTERFACE)) {
1916 // file does not exist, use original low res version
1917 strcpy(animation_filename, Ship_info[ship_class].anim_filename);
1918 mprintf(("Ship ANI: Can not find %s, using lowres version instead.\n", animation_filename));
1920 animation_filename[strlen(animation_filename) - 4] = '\0';
1921 mprintf(("SHIP ANI: Found hires version of %s\n",animation_filename));
1925 SDL_strlcpy(animation_filename, Ship_info[ship_class].anim_filename, SDL_arraysize(animation_filename));
1926 p_anim = anim_load(animation_filename);
1932 // ------------------------------------------------------------------------
1933 // start_ship_animation() will start a ship animation playing, and will
1934 // load the compressed anim from disk if required.
1935 void start_ship_animation(int ship_class, int play_sound)
1937 ss_icon_info *ss_icon;
1938 SDL_assert( ship_class >= 0 );
1940 if ( Ship_anim_class == ship_class )
1943 if ( Ship_anim_class >= 0 ) {
1944 stop_ship_animation();
1947 ss_icon = &Ss_icons[ship_class];
1949 // see if we need to load in the animation from disk
1950 if ( ss_icon->anim == NULL ) {
1951 ss_icon->anim = ss_load_individual_animation(ship_class);
1954 // see if we need to get an instance
1955 if ( ss_icon->anim_instance == NULL ) {
1956 anim_play_struct aps;
1958 anim_play_init(&aps, ss_icon->anim, Ship_anim_coords[gr_screen.res][0], Ship_anim_coords[gr_screen.res][1]);
1959 aps.screen_id = ON_SHIP_SELECT;
1960 aps.framerate_independent = 1;
1961 aps.skip_frames = 0;
1962 ss_icon->anim_instance = anim_play(&aps);
1965 Ship_anim_class = ship_class;
1967 // if ( play_sound ) {
1968 gamesnd_play_iface(SND_SHIP_ICON_CHANGE);
1972 // ------------------------------------------------------------------------
1973 // unload_ship_anims() will free all compressed anims from memory that were
1974 // loaded for the ship animations.
1977 void unload_ship_anims()
1979 for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1980 if ( Ss_icons[i].anim ) {
1981 anim_free(Ss_icons[i].anim);
1982 Ss_icons[i].anim = NULL;
1987 // ------------------------------------------------------------------------
1988 // unload_ship_anim_instances() will free any active ship animation instances.
1991 void unload_ship_anim_instances()
1993 for ( int i = 0; i < MAX_SHIP_TYPES; i++ ) {
1994 if ( Ss_icons[i].anim_instance ) {
1995 anim_release_render_instance(Ss_icons[i].anim_instance);
1996 Ss_icons[i].anim_instance = NULL;
2001 // ------------------------------------------------------------------------
2002 // commit_pressed() is called when the commit button from any of the briefing/ship select/ weapon
2003 // select screens is pressed. The ship selected is created, and the interface music is stopped.
2004 void commit_pressed()
2006 int player_ship_info_index;
2008 if ( Wss_num_wings > 0 ) {
2009 if(!(Game_mode & GM_MULTIPLAYER)){
2011 rc = create_wings();
2013 gamesnd_play_iface(SND_GENERAL_FAIL);
2020 if ( Selected_ss_class == -1 ) {
2021 player_ship_info_index = Team_data[Common_team].default_ship;
2024 SDL_assert(Selected_ss_class >= 0 );
2025 player_ship_info_index = Selected_ss_class;
2028 update_player_ship( player_ship_info_index );
2029 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[0]) == -1 ) {
2030 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
2035 // Check to ensure that the hotkeys are still pointing to valid objects. It is possible
2036 // for the player to assign a ship to a hotkey, then go and delete that ship in the
2037 // ship selection, and then try to start the mission. This function will detect those objects,
2038 // and remove them from the hotkey linked lists.
2039 mission_hotkey_validate();
2041 gamesnd_play_iface(SND_COMMIT_PRESSED);
2043 // save the player loadout
2044 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2045 SDL_strlcpy(Player_loadout.filename, Game_current_mission_filename, SDL_arraysize(Player_loadout.filename));
2046 SDL_strlcpy(Player_loadout.last_modified, The_mission.modified, SDL_arraysize(Player_loadout.last_modified));
2050 // move to the next stage
2051 // in multiplayer this is the final mission sync
2052 if(Game_mode & GM_MULTIPLAYER){
2053 Multi_sync_mode = MULTI_SYNC_POST_BRIEFING;
2054 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2056 // otherwise tell the standalone to move everyone into this state and continue
2057 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2058 send_mission_sync_packet(MULTI_SYNC_POST_BRIEFING);
2061 // in single player we jump directly into the mission
2063 gameseq_post_event(GS_EVENT_ENTER_GAME);
2067 // ------------------------------------------------------------------------
2068 // pick_from_ship_list() will determine if an icon from the ship selection
2069 // list can be picked up (for drag and drop). It calculates the difference
2070 // in x & y between the icon and the mouse, so we can move the icon with the
2071 // mouse in a realistic way
2072 int pick_from_ship_list(int screen_offset, int ship_class)
2075 SDL_assert(ship_class >= 0);
2077 if ( Wss_num_wings == 0 )
2080 // If carrying an icon, then do nothing
2081 if ( ss_icon_being_carried() )
2084 if ( Ss_pool[ship_class] > 0 ) {
2085 int mouse_x, mouse_y;
2087 ss_set_carried_icon(-1, ship_class);
2088 mouse_get_pos( &mouse_x, &mouse_y );
2089 Ss_delta_x = Ship_list_coords[gr_screen.res][screen_offset][0] - mouse_x;
2090 Ss_delta_y = Ship_list_coords[gr_screen.res][screen_offset][1] - mouse_y;
2091 SDL_assert( Ss_pool[ship_class] >= 0 );
2095 common_flash_button_init();
2099 // ------------------------------------------------------------------------
2100 // pick_from_wing() will determine if an icon from the wing formation (wb_num)
2101 // and slot number (ws_num) can be picked up (for drag and drop). It calculates
2102 // the difference in x & y between the icon and the mouse, so we can move the icon with the
2103 // mouse in a realistic way
2104 void pick_from_wing(int wb_num, int ws_num)
2107 SDL_assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
2108 SDL_assert(ws_num >= 0 && ws_num < MAX_WING_SLOTS);
2112 wb = &Ss_wings[wb_num];
2113 ws = &wb->ss_slots[ws_num];
2114 slot_index = wb_num*4+ws_num;
2116 if ( wb->wingnum < 0 )
2119 // Take care of case where the mouse button goes from up to down in one frame while
2121 if ( Drop_on_wing_mflag && ss_icon_being_carried() ) {
2122 if ( !ss_disabled_slot(slot_index) ) {
2123 ss_drop(Carried_ss_icon.from_slot, Carried_ss_icon.ship_class, slot_index, -1);
2124 ss_reset_carried_icon();
2125 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2129 if ( ss_icon_being_carried() )
2132 if ( ss_disabled_slot(slot_index) ) {
2136 switch ( ws->status ) {
2137 case WING_SLOT_DISABLED:
2138 case WING_SLOT_IGNORE:
2142 case WING_SLOT_EMPTY:
2143 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2144 // TODO: add fail sound
2148 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2149 case WING_SLOT_FILLED:
2151 int mouse_x, mouse_y;
2152 SDL_assert(Wss_slots[slot_index].ship_class >= 0);
2153 ss_set_carried_icon(slot_index, Wss_slots[slot_index].ship_class);
2155 mouse_get_pos( &mouse_x, &mouse_y );
2156 Ss_delta_x = Wing_icon_coords[gr_screen.res][slot_index][0] - mouse_x;
2157 Ss_delta_y = Wing_icon_coords[gr_screen.res][slot_index][1] - mouse_y;
2158 Carried_ss_icon.from_x = mouse_x;
2159 Carried_ss_icon.from_y = mouse_y;
2169 common_flash_button_init();
2172 // ------------------------------------------------------------------------
2173 // draw_wing_block() will draw the wing icons for the wing formation number
2174 // passed in as a parameter.
2176 // input: wb_num => wing block number (numbering starts at 0)
2177 // hot_slot => index of slot that mouse is over
2178 // selected_slot => index of slot that is selected
2179 // class_select => all ships of this class are drawn selected (send -1 to not use)
2180 void draw_wing_block(int wb_num, int hot_slot, int selected_slot, int class_select)
2186 int i, bitmap_to_draw, w, h, sx, sy, slot_index;
2188 SDL_assert(wb_num >= 0 && wb_num < MAX_WING_BLOCKS);
2189 wb = &Ss_wings[wb_num];
2191 if ( wb->wingnum == -1 )
2194 // print the wing name under the wing
2195 wp = &Wings[wb->wingnum];
2196 gr_get_string_size(&w, &h, wp->name);
2197 sx = Wing_icon_coords[gr_screen.res][wb_num*4][0] + 16 - w/2;
2198 sy = Wing_icon_coords[gr_screen.res][wb_num*4 + 3][1] + 32 + h;
2199 gr_set_color_fast(&Color_normal);
2200 gr_string(sx, sy, wp->name);
2202 for ( i = 0; i < MAX_WING_SLOTS; i++ ) {
2203 bitmap_to_draw = -1;
2204 ws = &wb->ss_slots[i];
2205 slot_index = wb_num*4 + i;
2207 if ( Wss_slots[slot_index].ship_class >= 0 ) {
2208 icon = &Ss_icons[Wss_slots[slot_index].ship_class];
2213 switch(ws->status & ~WING_SLOT_LOCKED ) {
2214 case WING_SLOT_FILLED:
2215 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2219 if ( class_select >= 0 ) { // only ship select
2220 if ( Carried_ss_icon.from_slot == slot_index ) {
2221 if ( ss_carried_icon_moved() ) {
2222 bitmap_to_draw = Wing_slot_empty_bitmap;
2224 bitmap_to_draw = -1;
2230 if ( ws->status & WING_SLOT_LOCKED ) {
2231 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2233 // in multiplayer, determine if this it the special case where the slot is disabled, and
2234 // it is also _my_ slot (ie, team capatains/host have not locked players yet)
2235 if((Game_mode & GM_MULTIPLAYER) && multi_ts_disabled_high_slot(slot_index)){
2236 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED_HIGH];
2242 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_NORMAL];
2243 if ( selected_slot == slot_index || class_select == Wss_slots[slot_index].ship_class) {
2244 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2245 } else if ( hot_slot == slot_index ) {
2246 if ( mouse_down(MOUSE_LEFT_BUTTON) ){
2247 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_SELECTED];
2249 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_HOT];
2253 if ( ws->status & WING_SLOT_IS_PLAYER && (selected_slot != slot_index) ) {
2254 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_PLAYER];
2258 case WING_SLOT_EMPTY:
2259 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2260 bitmap_to_draw = Wing_slot_empty_bitmap;
2263 case WING_SLOT_DISABLED:
2264 case WING_SLOT_IGNORE:
2266 bitmap_to_draw = icon->icon_bmaps[ICON_FRAME_DISABLED];
2268 bitmap_to_draw = Wing_slot_disabled_bitmap;
2279 if ( bitmap_to_draw != -1 ) {
2280 gr_set_bitmap(bitmap_to_draw, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2281 gr_bitmap(Wing_icon_coords[gr_screen.res][slot_index][0], Wing_icon_coords[gr_screen.res][slot_index][1]);
2286 // called by multiplayer team select to set the slot based flags
2287 void ss_make_slot_empty(int slot_index)
2289 int wing_num,slot_num;
2293 // calculate the wing #
2294 wing_num = slot_index / 4;
2295 slot_num = slot_index % 4;
2297 // get the wing and slot entries
2298 wb = &Ss_wings[wing_num];
2299 ws = &wb->ss_slots[slot_num];
2302 ws->status &= ~(WING_SLOT_FILLED | WING_SLOT_DISABLED);
2303 ws->status |= WING_SLOT_EMPTY;
2306 // called by multiplayer team select to set the slot based flags
2307 void ss_make_slot_full(int slot_index)
2309 int wing_num,slot_num;
2313 // calculate the wing #
2314 wing_num = slot_index / 4;
2315 slot_num = slot_index % 4;
2317 // get the wing and slot entries
2318 wb = &Ss_wings[wing_num];
2319 ws = &wb->ss_slots[slot_num];
2322 ws->status &= ~(WING_SLOT_EMPTY | WING_SLOT_DISABLED);
2323 ws->status |= WING_SLOT_FILLED;
2326 void ss_blit_ship_icon(int x,int y,int ship_class,int bmap_num)
2328 // blit the bitmap in the correct location
2329 if(ship_class == -1){
2330 gr_set_bitmap(Wing_slot_empty_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2332 ss_icon_info *icon = &Ss_icons[ship_class];
2333 SDL_assert(icon->icon_bmaps[bmap_num] != -1);
2334 gr_set_bitmap(icon->icon_bmaps[bmap_num], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2339 // ------------------------------------------------------------------------
2340 // unload_ship_icons() frees the memory that was used to hold the bitmaps
2343 void unload_wing_icons()
2345 if ( Wing_slot_empty_bitmap != -1 ) {
2346 bm_release(Wing_slot_empty_bitmap);
2347 Wing_slot_empty_bitmap = -1;
2350 if ( Wing_slot_disabled_bitmap != -1 ) {
2351 bm_release(Wing_slot_disabled_bitmap);
2352 Wing_slot_disabled_bitmap = -1;
2356 // ------------------------------------------------------------------------
2357 // create_wings() will ensure the correct ships are in the player wings
2358 // for the game. It works by calling change_ship_type() on the wing ships
2359 // so they match what the player selected. ship_create() is called for the
2360 // player ship (and current_count, ship_index[] is updated), since it is not yet
2361 // part of the wing structure.
2363 // returns: 0 ==> success
2372 int shipnum, slot_index;
2373 int cleanup_ship_index[MAX_WING_SLOTS];
2377 for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2381 if ( wb->wingnum == -1 )
2384 wp = &Wings[wb->wingnum];
2386 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2388 ws = &wb->ss_slots[j];
2389 switch ( ws->status ) {
2391 case WING_SLOT_FILLED:
2392 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER:
2393 case WING_SLOT_FILLED|WING_SLOT_LOCKED:
2394 case WING_SLOT_FILLED|WING_SLOT_IS_PLAYER|WING_SLOT_LOCKED:
2395 if ( wp->ship_index[j] >= 0 ) {
2396 SDL_assert(Ships[wp->ship_index[j]].objnum >= 0);
2399 if ( ws->status & WING_SLOT_IS_PLAYER ) {
2400 update_player_ship(Wss_slots[slot_index].ship_class);
2402 if ( wl_update_ship_weapons(Ships[Player_obj->instance].objnum, &Wss_slots[i*4+j]) == -1 ) {
2403 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player ship has no weapons", 461));
2409 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2410 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2411 if ( ws->sa_index == (p_objp-ship_arrivals) ) {
2412 p_objp->ship_class = Wss_slots[slot_index].ship_class;
2413 wl_update_parse_object_weapons(p_objp, &Wss_slots[i*4+j]);
2419 SDL_assert(found_pobj);
2423 // Change the ship type of the ship if different than current.
2424 // NOTE: This will reset the weapons for this ship. I think this is
2425 // the right thing to do, since the ships may have different numbers
2426 // of weapons and may not have the same allowed weapon types
2427 if ( Ships[wp->ship_index[j]].ship_info_index != Wss_slots[slot_index].ship_class )
2428 change_ship_type(wp->ship_index[j], Wss_slots[slot_index].ship_class);
2429 wl_update_ship_weapons(Ships[wp->ship_index[j]].objnum, &Wss_slots[i*4+j]);
2435 case WING_SLOT_EMPTY:
2436 case WING_SLOT_EMPTY|WING_SLOT_IS_PLAYER:
2437 if ( ws->status & WING_SLOT_IS_PLAYER ) {
2438 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Player %s must select a place in player wing", 462), Player->callsign);
2446 } // end for (wing slot)
2447 } // end for (wing block)
2449 for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
2451 wp = &Wings[wb->wingnum];
2453 if ( wb->wingnum == -1 )
2456 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2457 cleanup_ship_index[k] = -1;
2460 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
2461 ws = &wb->ss_slots[j];
2462 switch( ws->status ) {
2463 case WING_SLOT_EMPTY:
2464 // delete ship that is not going to be used by the wing
2465 if ( wb->is_late ) {
2466 list_remove( &ship_arrival_list, &ship_arrivals[ws->sa_index]);
2468 SDL_assert(wp->wave_count >= 0);
2471 shipnum = wp->ship_index[j];
2472 SDL_assert( shipnum >= 0 && shipnum < MAX_SHIPS );
2473 cleanup_ship_index[j] = shipnum;
2474 ship_add_exited_ship( &Ships[shipnum], SEF_PLAYER_DELETED );
2475 obj_delete(Ships[shipnum].objnum);
2476 hud_set_wingman_status_none( Ships[shipnum].wing_status_wing_index, Ships[shipnum].wing_status_wing_pos);
2485 } // end for (wing slot)
2487 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
2488 if ( cleanup_ship_index[k] != -1 ) {
2489 ship_wing_cleanup( cleanup_ship_index[k], wp );
2493 } // end for (wing block)
2498 void ship_stop_animation()
2500 if ( Ship_anim_class >= 0 )
2501 stop_ship_animation();
2504 // ----------------------------------------------------------------------------
2505 // update_player_ship()
2507 // Updates the ship class of the player ship
2509 // parameters: si_index => ship info index of ship class to change to
2512 void update_player_ship(int si_index)
2514 SDL_assert( si_index >= 0 );
2515 SDL_assert( Player_obj != NULL);
2518 // Change the ship type of the player ship if different than current.
2519 // NOTE: This will reset the weapons for this ship. I think this is
2520 // the right thing to do, since the ships may have different numbers
2521 // of weapons and may not have the same allowed weapon types
2522 if ( Player_ship->ship_info_index != si_index )
2523 change_ship_type(Player_obj->instance, si_index);
2525 Player->last_ship_flown_si_index = si_index;
2528 // ----------------------------------------------------------------------------
2529 // create a default player ship
2531 // parameters: use_last_flown => select ship that was last flown on a mission
2532 // (this is a default parameter which is set to 1)
2534 // returns: 0 => success
2537 int create_default_player_ship(int use_last_flown)
2539 int player_ship_class=-1, i;
2541 // find the ship that matches the string stored in default_player_ship
2543 if ( use_last_flown ) {
2544 player_ship_class = Players[Player_num].last_ship_flown_si_index;
2547 for (i = 0; i < Num_ship_types; i++) {
2548 if ( !SDL_strcasecmp(Ship_info[i].name, default_player_ship) ) {
2549 player_ship_class = i;
2550 Players[Player_num].last_ship_flown_si_index = player_ship_class;
2555 if (i == Num_ship_types)
2559 update_player_ship(player_ship_class);
2561 // debug code to keep using descent style physics if the player starts a new game
2563 if ( use_descent ) {
2565 toggle_player_object();
2572 // return the original ship class for the specified slot
2573 int ss_return_original_ship_class(int slot_num)
2580 return Ss_wings[wnum].ss_slots[snum].original_ship_class;
2583 // return the ship arrival index for the slot (-1 means no ship arrival index)
2584 int ss_return_saindex(int slot_num)
2591 return Ss_wings[wnum].ss_slots[snum].sa_index;
2594 // ----------------------------------------------------------------------------
2597 // For a given wing slot, return the ship index if the ship has been created.
2598 // Otherwise, find the index into ship_arrivals[] for the ship
2600 // input: wing_block => wing block of ship to find
2601 // wing_slot => wing slot of ship to find
2602 // ship_index => OUTPUT parameter: the Ships[] index of the ship in the wing slot
2603 // This value will be -1 if there is no ship created yet
2604 // ppobjp => OUTPUT parameter: returns a pointer to a parse object for
2605 // the ship that hasn't been created yet. Set to NULL if the
2606 // ship has already been created
2608 // returns: the original ship class of the ship, or -1 if the ship doesn't exist
2610 // NOTE: For the player wing, the player is not yet in the wp->ship_index[].. so
2611 // that is why there is an offset of 1 when getting ship indicies from the player
2612 // wing. The player is special cased by looking at the status of the wing slot
2614 int ss_return_ship(int wing_block, int wing_slot, int *ship_index, p_object **ppobjp)
2621 if (!Wss_num_wings) {
2623 *ship_index = Player_obj->instance;
2624 return Player_ship->ship_info_index;
2627 if ( Ss_wings[wing_block].wingnum < 0 ) {
2631 ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2633 // Check to see if ship is on the ship_arrivals[] list
2634 if ( ws->sa_index != -1 ) {
2636 *ppobjp = &ship_arrivals[ws->sa_index];
2638 *ship_index = Wings[Ss_wings[wing_block].wingnum].ship_index[wing_slot];
2639 SDL_assert(*ship_index != -1);
2642 return ws->original_ship_class;
2645 // return the name of the ship in the specified wing position... if the ship is the
2646 // player ship, return the player callsign
2648 // input: ensure at least NAME_LENGTH bytes allocated for name buffer
2649 void ss_return_name(int wing_block, int wing_slot, char *name, const int max_namelen)
2654 ws = &Ss_wings[wing_block].ss_slots[wing_slot];
2655 wp = &Wings[Ss_wings[wing_block].wingnum];
2657 if (!Wss_num_wings) {
2658 SDL_strlcpy(name, Player->callsign, max_namelen);
2662 // Check to see if ship is on the ship_arrivals[] list
2663 if ( ws->sa_index != -1 ) {
2664 SDL_strlcpy(name, ship_arrivals[ws->sa_index].name, max_namelen);
2667 sp = &Ships[wp->ship_index[wing_slot]];
2669 // in multiplayer, return the callsigns of the players who are in the ships
2670 if(Game_mode & GM_MULTIPLAYER){
2671 int player_index = multi_find_player_by_object(&Objects[sp->objnum]);
2672 if(player_index != -1){
2673 SDL_strlcpy(name,Net_players[player_index].player->callsign, max_namelen);
2675 SDL_strlcpy(name,sp->ship_name, max_namelen);
2678 SDL_strlcpy(name, sp->ship_name, max_namelen);
2683 int ss_get_selected_ship()
2685 return Selected_ss_class;
2688 // Set selected ship to the first occupied wing slot, or first ship in pool if no slots are occupied
2689 void ss_reset_selected_ship()
2693 Selected_ss_class = -1;
2695 if ( Wss_num_wings <= 0 ) {
2696 Selected_ss_class = Team_data[Common_team].default_ship;
2700 // get first ship class found on slots
2701 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2702 if ( Wss_slots[i].ship_class >= 0 ) {
2703 Selected_ss_class = Wss_slots[i].ship_class;
2708 if ( Selected_ss_class == -1 ) {
2710 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2711 if ( Ss_pool[i] > 0 ) {
2712 Selected_ss_class = i;
2717 if ( Selected_ss_class == -1 ) {
2723 // There may be ships that are in wings but not in Team_data[0]. Since we still want to show those
2724 // icons in the ship selection list, the code below checks for these cases. If a ship is found in
2725 // a wing, and is not in Team_data[0], it is appended to the end of the ship_count[] and ship_list[] arrays
2726 // that are in Team_data[0]
2728 // exit: number of distinct ship classes available to choose from
2729 int ss_fixup_team_data(team_data *tdata)
2731 int i, j, k, ship_in_parse_player = 0, list_size;
2733 team_data *p_team_data;
2735 p_team_data = tdata;
2736 list_size = p_team_data->number_choices;
2738 for ( i = 0; i < MAX_PLAYER_WINGS; i++ ) {
2740 if ( Starting_wings[i] == -1 )
2742 wp = &Wings[Starting_wings[i]];
2743 for ( j = 0; j < wp->current_count; j++ ) {
2744 ship_in_parse_player = 0;
2746 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2747 SDL_assert( p_team_data->ship_count[k] >= 0 );
2748 if ( p_team_data->ship_list[k] == Ships[wp->ship_index[j]].ship_info_index ) {
2749 ship_in_parse_player = 1;
2752 } // end for, go to next item in parse player
2754 if ( !ship_in_parse_player ) {
2755 p_team_data->ship_count[list_size] = 0;
2756 p_team_data->ship_list[list_size] = Ships[wp->ship_index[j]].ship_info_index;
2757 p_team_data->number_choices++;
2760 } // end for, go get next ship in wing
2762 if ( wp->current_count == 0 ) {
2764 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2765 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2766 ship_in_parse_player = 0;
2768 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2769 SDL_assert( p_team_data->ship_count[k] >= 0 );
2770 if ( p_team_data->ship_list[k] == p_objp->ship_class ) {
2771 ship_in_parse_player = 1;
2774 } // end for, go to next item in parse player
2776 if ( !ship_in_parse_player ) {
2777 p_team_data->ship_count[list_size] = 0;
2778 p_team_data->ship_list[list_size] = p_objp->ship_class;
2779 p_team_data->number_choices++;
2785 } // end for, go to next wing
2787 if ( list_size == 0 ) {
2788 // ensure that the default player ship is in the ship_list too
2789 ship_in_parse_player = 0;
2790 for ( k = 0; k < p_team_data->number_choices; k++ ) {
2791 SDL_assert( p_team_data->ship_count[k] >= 0 );
2792 if ( p_team_data->ship_list[k] == p_team_data->default_ship ) {
2793 ship_in_parse_player = 1;
2797 if ( !ship_in_parse_player ) {
2798 p_team_data->ship_count[list_size] = 0;
2799 p_team_data->ship_list[list_size] = p_team_data->default_ship;
2800 p_team_data->number_choices++;
2808 // set numbers of ships in pool to default values
2809 void ss_init_pool(team_data *pteam)
2813 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2817 // set number of available ships based on counts in team_data
2818 for ( i = 0; i < pteam->number_choices; i++ ) {
2819 Ss_pool[pteam->ship_list[i]] = pteam->ship_count[i];
2823 // load the icons for a specific ship class
2824 void ss_load_icons(int ship_class)
2827 int first_frame, num_frames, i;
2829 icon = &Ss_icons[ship_class];
2831 first_frame = bm_load_animation(Ship_info[ship_class].icon_filename, &num_frames);
2832 if ( first_frame == -1 ) {
2833 Int3(); // Could not load in icon frames.. get Alan
2837 for ( i = 0; i < num_frames; i++ ) {
2838 icon->icon_bmaps[i] = first_frame+i;
2841 // set the current bitmap for the ship icon
2842 icon->current_icon_bitmap = icon->icon_bmaps[ICON_FRAME_NORMAL];
2845 // load all the icons for ships in the pool
2846 void ss_load_all_icons()
2848 #ifndef DEMO // not for FS2_DEMO
2852 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2854 Ss_icons[i].current_icon_bitmap = -1;
2855 Ss_icons[i].anim = NULL;
2856 Ss_icons[i].anim_instance = NULL;
2857 for ( j = 0; j < NUM_ICON_FRAMES; j++ ) {
2858 Ss_icons[i].icon_bmaps[j] = -1;
2861 if ( Ss_pool[i] >= 0 ) {
2869 // Load in a specific ship animation. The data is loaded as a memory-mapped file since these animations
2871 void ss_load_anim(int ship_class)
2875 icon = &Ss_icons[ship_class];
2877 // load the compressed ship animation into memory
2878 // NOTE: if last parm of load_anim is 1, the anim file is mapped to memory
2879 SDL_assert( icon->anim == NULL );
2880 icon->anim = ss_load_individual_animation(ship_class);
2881 if ( icon->anim == NULL ) {
2882 Int3(); // couldn't load anim filename.. get Alan
2886 // Load in any ship animations. This function assumes that Ss_pool has been inited.
2887 void ss_load_all_anims()
2889 #ifndef DEMO // not for FS2_DEMO
2893 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
2894 if ( Ss_pool[i] > 0 ) {
2902 // determine if the slot is disabled
2903 int ss_disabled_slot(int slot_num)
2905 if ( Wss_num_wings <= 0 ){
2909 // HACK HACK HACK - call the team select function in multiplayer
2910 if(Game_mode & GM_MULTIPLAYER) {
2911 return multi_ts_disabled_slot(slot_num);
2913 return ( Ss_wings[slot_num/4].ss_slots[slot_num%4].status & WING_SLOT_IGNORE );
2916 // reset the slot data
2917 void ss_clear_slots()
2922 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
2923 Wss_slots[i].ship_class = -1;
2926 for ( i = 0; i < 3; i++ ) {
2927 for ( j = 0; j < 4; j++ ) {
2928 slot = &Ss_wings[i].ss_slots[j];
2929 slot->status = WING_SLOT_DISABLED;
2930 slot->sa_index = -1;
2931 slot->original_ship_class = -1;
2936 // initialize all wing struct stuff
2937 void ss_clear_wings()
2941 for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
2942 Ss_wings[idx].wingnum = -1;
2943 Ss_wings[idx].num_slots = 0;
2944 Ss_wings[idx].is_late = 0;
2948 // set up Wss_num_wings and Wss_wings[] based on Starting_wings[] info
2949 void ss_init_wing_info(int wing_num,int starting_wing_num)
2952 ss_wing_info *ss_wing;
2955 ss_wing = &Ss_wings[wing_num];
2957 if ( Starting_wings[starting_wing_num] < 0 ) {
2961 ss_wing->wingnum = Starting_wings[starting_wing_num];
2964 wp = &Wings[Ss_wings[wing_num].wingnum];
2965 ss_wing->num_slots = wp->current_count;
2967 if ( wp->current_count == 0 || wp->ship_index[0] == -1 ) {
2969 // Temporarily fill in the current count and initialize the ship list in the wing
2970 // This gets cleaned up before the mission is started
2971 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
2972 if ( p_objp->wingnum == WING_INDEX(wp) ) {
2973 slot = &ss_wing->ss_slots[ss_wing->num_slots++];
2974 slot->sa_index = p_objp-ship_arrivals;
2975 slot->original_ship_class = p_objp->ship_class;
2977 ss_wing->is_late = 1;
2982 // Determine if a ship is actually a console player ship
2983 int ss_wing_slot_is_console_player(int index)
2985 int wingnum, slotnum;
2990 if ( wingnum >= Wss_num_wings ) {
2994 if ( Ss_wings[wingnum].ss_slots[slotnum].status & WING_SLOT_IS_PLAYER ) {
3001 // init the ship selection portion of the units, and set up the ui data
3002 void ss_init_units()
3006 ss_slot_info *ss_slot;
3007 ss_wing_info *ss_wing;
3009 for ( i = 0; i < Wss_num_wings; i++ ) {
3011 ss_wing = &Ss_wings[i];
3013 if ( ss_wing->wingnum < 0 ) {
3018 wp = &Wings[ss_wing->wingnum];
3020 for ( j = 0; j < ss_wing->num_slots; j++ ) {
3022 ss_slot = &ss_wing->ss_slots[j];
3024 if ( ss_slot->sa_index == -1 ) {
3025 ss_slot->original_ship_class = Ships[wp->ship_index[j]].ship_info_index;
3028 // Set the type of slot. Check if the slot is marked as locked, if so then the player is not
3029 // going to be able to modify that ship.
3030 if ( ss_slot->sa_index == -1 ) {
3032 if ( Ships[wp->ship_index[j]].flags & SF_LOCKED ) {
3033 ss_slot->status = WING_SLOT_DISABLED;
3034 ss_slot->status |= WING_SLOT_LOCKED;
3036 ss_slot->status = WING_SLOT_FILLED;
3039 objnum = Ships[wp->ship_index[j]].objnum;
3040 if ( Objects[objnum].flags & OF_PLAYER_SHIP ) {
3041 if ( ss_slot->status & WING_SLOT_LOCKED ) {
3042 // Int3(); // Get Alan
3045 ss_slot->status &= ~(WING_SLOT_LOCKED);
3047 ss_slot->status = WING_SLOT_FILLED;
3048 if ( objnum == OBJ_INDEX(Player_obj) ) {
3049 ss_slot->status |= WING_SLOT_IS_PLAYER;
3053 if ( ship_arrivals[ss_slot->sa_index].flags & P_SF_LOCKED ) {
3054 ss_slot->status = WING_SLOT_DISABLED;
3055 ss_slot->status |= WING_SLOT_LOCKED;
3057 ss_slot->status = WING_SLOT_FILLED;
3059 if ( ship_arrivals[ss_slot->sa_index].flags & P_OF_PLAYER_START ) {
3060 if ( ss_slot->status & WING_SLOT_LOCKED ) {
3061 // Int3(); // Get Alan
3064 ss_slot->status &= ~(WING_SLOT_LOCKED);
3066 ss_slot->status = WING_SLOT_FILLED;
3067 ss_slot->status |= WING_SLOT_IS_PLAYER;
3071 // Assign the ship class to the unit
3072 Wss_slots[i*4+j].ship_class = ss_slot->original_ship_class;
3077 // lock/unlock any necessary slots for multiplayer
3078 if(Game_mode & GM_MULTIPLAYER){
3079 ss_recalc_multiplayer_slots();
3083 // set the necessary pointers
3084 void ss_set_team_pointers(int team)
3086 Ss_wings = Ss_wings_teams[team];
3087 Ss_icons = Ss_icons_teams[team];
3088 Ss_pool = Ss_pool_teams[team];
3089 Wl_pool = Wl_pool_teams[team];
3090 Wss_slots = Wss_slots_teams[team];
3093 // initialize team specific stuff
3094 void ship_select_init_team_data(int team_num)
3098 // set up the pointers to initialize the data structures.
3099 Ss_wings = Ss_wings_teams[team_num];
3100 Ss_icons = Ss_icons_teams[team_num];
3101 Ss_pool = Ss_pool_teams[team_num];
3102 Wl_pool = Wl_pool_teams[team_num];
3103 Wss_slots = Wss_slots_teams[team_num];
3105 ss_fixup_team_data(&Team_data[team_num]);
3106 ss_init_pool(&Team_data[team_num]);
3108 ss_clear_slots(); // reset data for slots
3111 // determine how many wings we should be checking for
3113 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3114 // now setup wings for easy reference
3115 ss_init_wing_info(0,team_num);
3117 // now setup wings for easy reference
3118 for(idx=0;idx<MAX_PLAYER_WINGS;idx++){
3119 ss_init_wing_info(idx,idx);
3124 // if there are no wings, don't call the init_units() function
3125 if ( Wss_num_wings <= 0 ) {
3126 Wss_slots[0].ship_class = Team_data[team_num].default_ship;
3133 // called when the briefing is entered
3134 void ship_select_common_init()
3138 // initialize team critical data for all teams
3139 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3140 // initialize for all teams in the game
3141 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
3142 ship_select_init_team_data(idx);
3145 // finally, intialize team data for myself
3146 ship_select_init_team_data(Common_team);
3148 ship_select_init_team_data(Common_team);
3153 // load the necessary icons/animations
3154 ss_load_all_icons();
3155 ss_load_all_anims();
3157 ss_reset_selected_ship();
3158 ss_reset_carried_icon();
3161 // change any interface data based on updated Wss_slots[] and Ss_pool[]
3162 void ss_synch_interface()
3167 int old_list_start = SS_active_list_start;
3169 init_active_list(); // build the list of pool ships
3171 if ( old_list_start < SS_active_list_size ) {
3172 SS_active_list_start = old_list_start;
3175 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
3176 slot = &Ss_wings[i/4].ss_slots[i%4];
3178 if ( Wss_slots[i].ship_class == -1 ) {
3179 if ( slot->status & WING_SLOT_FILLED ) {
3180 slot->status &= ~WING_SLOT_FILLED;
3181 slot->status |= WING_SLOT_EMPTY;
3184 if ( slot->status & WING_SLOT_EMPTY ) {
3185 slot->status &= ~WING_SLOT_EMPTY;
3186 slot->status |= WING_SLOT_FILLED;
3192 // exit: data changed flag
3193 int ss_swap_slot_slot(int from_slot, int to_slot, int *sound)
3197 if ( from_slot == to_slot ) {
3198 *sound=SND_ICON_DROP_ON_WING;
3202 // ensure from_slot has a ship to pick up
3203 if ( Wss_slots[from_slot].ship_class < 0 ) {
3204 *sound=SND_ICON_DROP;
3209 tmp = Wss_slots[from_slot].ship_class;
3210 Wss_slots[from_slot].ship_class = Wss_slots[to_slot].ship_class;
3211 Wss_slots[to_slot].ship_class = tmp;
3214 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3215 tmp = Wss_slots[from_slot].wep[i];
3216 Wss_slots[from_slot].wep[i] = Wss_slots[to_slot].wep[i];
3217 Wss_slots[to_slot].wep[i] = tmp;
3219 tmp = Wss_slots[from_slot].wep_count[i];
3220 Wss_slots[from_slot].wep_count[i] = Wss_slots[to_slot].wep_count[i];
3221 Wss_slots[to_slot].wep_count[i] = tmp;
3224 *sound=SND_ICON_DROP_ON_WING;
3228 // exit: data changed flag
3229 int ss_dump_to_list(int from_slot, int to_list, int *sound)
3234 slot = &Wss_slots[from_slot];
3236 // ensure from_slot has a ship to pick up
3237 if ( slot->ship_class < 0 ) {
3238 *sound=SND_ICON_DROP;
3242 // put ship back in list
3243 Ss_pool[to_list]++; // return to list
3244 slot->ship_class = -1; // remove from slot
3246 // put weapons back in list
3247 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3248 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3249 Wl_pool[slot->wep[i]] += slot->wep_count[i];
3251 slot->wep_count[i] = 0;
3255 *sound=SND_ICON_DROP;
3259 // exit: data changed flag
3260 int ss_grab_from_list(int from_list, int to_slot, int *sound)
3263 int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3265 slot = &Wss_slots[to_slot];
3267 // ensure that pool has ship
3268 if ( Ss_pool[from_list] <= 0 ) {
3269 *sound=SND_ICON_DROP;
3273 SDL_assert(slot->ship_class < 0 ); // slot should be empty
3275 // take ship from list->slot
3276 Ss_pool[from_list]--;
3277 slot->ship_class = from_list;
3279 // take weapons from list->slot
3280 wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3281 wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3282 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3283 slot->wep[i] = wep[i];
3284 slot->wep_count[i] = wep_count[i];
3287 *sound=SND_ICON_DROP_ON_WING;
3291 // exit: data changed flag
3292 int ss_swap_list_slot(int from_list, int to_slot, int *sound)
3294 int i, wep[MAX_WL_WEAPONS], wep_count[MAX_WL_WEAPONS];
3297 // ensure that pool has ship
3298 if ( Ss_pool[from_list] <= 0 ) {
3299 *sound=SND_ICON_DROP;
3303 slot = &Wss_slots[to_slot];
3304 SDL_assert(slot->ship_class >= 0 ); // slot should be filled
3306 // put ship from slot->list
3307 Ss_pool[Wss_slots[to_slot].ship_class]++;
3309 // put weapons from slot->list
3310 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3311 if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) {
3312 Wl_pool[slot->wep[i]] += slot->wep_count[i];
3314 slot->wep_count[i] = 0;
3318 // take ship from list->slot
3319 Ss_pool[from_list]--;
3320 slot->ship_class = from_list;
3322 // take weapons from list->slot
3323 wl_get_default_weapons(from_list, to_slot, wep, wep_count);
3324 wl_remove_weps_from_pool(wep, wep_count, slot->ship_class);
3325 for ( i = 0; i < MAX_WL_WEAPONS; i++ ) {
3326 slot->wep[i] = wep[i];
3327 slot->wep_count[i] = wep_count[i];
3330 *sound=SND_ICON_DROP_ON_WING;
3334 void ss_apply(int mode, int from_slot, int from_list, int to_slot, int to_list,int player_index)
3340 case WSS_SWAP_SLOT_SLOT:
3341 update = ss_swap_slot_slot(from_slot, to_slot, &sound);
3343 case WSS_DUMP_TO_LIST:
3344 update = ss_dump_to_list(from_slot, to_list, &sound);
3346 case WSS_GRAB_FROM_LIST:
3347 update = ss_grab_from_list(from_list, to_slot, &sound);
3349 case WSS_SWAP_LIST_SLOT:
3350 update = ss_swap_list_slot(from_list, to_slot, &sound);
3354 // only play this sound if the move was done locally (by the host in other words)
3355 if ( (sound >= 0) && (player_index == -1) ) {
3356 gamesnd_play_iface(sound);
3360 // NO LONGER USED - THERE IS A MULTIPLAYER VERSION OF THIS SCREEN NOW
3362 if ( MULTIPLAYER_HOST ) {
3364 ubyte wss_data[MAX_PACKET_SIZE-20];
3365 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound);
3366 send_wss_update_packet(wss_data, size, player_index);
3370 ss_synch_interface();
3374 void ss_drop(int from_slot,int from_list,int to_slot,int to_list,int player_index)
3377 common_flash_button_init();
3379 mode = wss_get_mode(from_slot, from_list, to_slot, to_list, -1);
3381 ss_apply(mode, from_slot, from_list, to_slot, to_list,player_index);
3385 // lock/unlock any necessary slots for multiplayer
3386 void ss_recalc_multiplayer_slots()
3389 ss_slot_info *ss_slot;
3390 ss_wing_info *ss_wing;
3393 if ( Wss_num_wings <= 0 ) {
3394 Wss_slots[0].ship_class = Team_data[Common_team].default_ship;;
3398 for ( i = 0; i < Wss_num_wings; i++ ) {
3399 ss_wing = &Ss_wings[i];
3400 if ( ss_wing->wingnum < 0 ) {
3405 // NOTE : the method below will eventually have to change to account for all possible netgame options
3407 // get the wing pointer
3408 for ( j = 0; j < ss_wing->num_slots; j++ ) {
3409 // get the slot pointer
3410 ss_slot = &ss_wing->ss_slots[j];
3412 if (ss_slot->sa_index == -1) {
3413 // lock all slots by default
3414 ss_slot->status |= WING_SLOT_LOCKED;
3416 // if this is my slot, then unlock it
3417 if(!multi_ts_disabled_slot((i*4)+j)){
3418 ss_slot->status &= ~WING_SLOT_LOCKED;