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/Network/MultiTeamSelect.cpp $
15 * Multiplayer Team Selection Code
18 * Revision 1.8 2005/10/02 09:30:10 taylor
19 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
21 * Revision 1.7 2004/09/20 01:31:44 theoddone33
24 * Revision 1.6 2004/06/11 01:51:13 tigital
25 * byte-swapping changes for bigendian systems
27 * Revision 1.5 2003/05/25 02:30:43 taylor
30 * Revision 1.4 2002/06/17 06:33:10 relnev
31 * ryan's struct patch for gcc 2.95
33 * Revision 1.3 2002/06/09 04:41:24 relnev
34 * added copyright header
36 * Revision 1.2 2002/05/07 03:16:47 theoddone33
37 * The Great Newline Fix
39 * Revision 1.1.1.1 2002/05/03 03:28:10 root
43 * 27 9/13/99 12:54p Jefff
46 * 26 9/12/99 3:21p Jefff
47 * commit button coord fix in 640
49 * 25 8/05/99 9:57p Jefff
50 * fixed some button wierdness
52 * 24 8/05/99 5:08p Jefff
53 * fixed some location probs
55 * 23 7/28/99 5:34p Dave
56 * Nailed the missing stats bug to the wall. Problem was optimized build
57 * and using GET_DATA() with array elements. BLECH.
59 * 22 7/24/99 6:02p Jefff
60 * Added "lock" text to lock button
62 * 21 5/03/99 8:32p Dave
63 * New version of multi host options screen.
65 * 20 3/25/99 6:36p Neilk
66 * more hires coord fixes
68 * 19 3/25/99 2:44p Neilk
71 * 18 3/23/99 11:56a Neilk
72 * new source safe checkin
74 * 17 3/10/99 6:50p Dave
75 * Changed the way we buffer packets for all clients. Optimized turret
76 * fired packets. Did some weapon firing optimizations.
78 * 16 3/09/99 6:24p Dave
79 * More work on object update revamping. Identified several sources of
80 * unnecessary bandwidth.
82 * 15 2/21/99 6:02p Dave
83 * Fixed standalone WSS packets.
85 * 14 2/11/99 3:08p Dave
86 * PXO refresh button. Very preliminary squad war support.
88 * 13 2/01/99 5:55p Dave
89 * Removed the idea of explicit bitmaps for buttons. Fixed text
90 * highlighting for disabled gadgets.
92 * 12 1/30/99 5:08p Dave
93 * More new hi-res stuff.Support for nice D3D textures.
95 * 11 1/30/99 1:29a Dave
96 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
97 * screen. Fixed beam weapon death messages.
99 * 10 1/29/99 5:07p Dave
100 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
103 * 9 1/13/99 7:19p Neilk
104 * Converted Mission Brief, Barracks, Synch to high res support
106 * 8 12/18/98 1:13a Dave
107 * Rough 1024x768 support for Direct3D. Proper detection and usage through
110 * 7 11/30/98 1:07p Dave
111 * 16 bit conversion, first run.
113 * 6 11/19/98 8:04a Dave
114 * Full support for D3-style reliable sockets. Revamped packet lag/loss
115 * system, made it receiver side and at the lowest possible level.
117 * 5 11/17/98 11:12a Dave
118 * Removed player identification by address. Now assign explicit id #'s.
120 * 4 11/05/98 5:55p Dave
121 * Big pass at reducing #includes
123 * 3 10/13/98 9:29a Dave
124 * Started neatening up freespace.h. Many variables renamed and
125 * reorganized. Added AlphaColors.[h,cpp]
127 * 2 10/07/98 10:53a Dave
130 * 1 10/07/98 10:50a Dave
132 * 112 9/18/98 2:22a Dave
133 * Fixed freespace-side PXO api to correctly handle length 10 id strings.
134 * Fixed team select screen to handle alpha/beta/gamma ships which are not
135 * marked as OF_PLAYER_SHIP
137 * 111 9/17/98 3:08p Dave
138 * PXO to non-pxo game warning popup. Player icon stuff in create and join
139 * game screens. Upped server count refresh time in PXO to 35 secs (from
142 * 110 8/20/98 5:31p Dave
143 * Put in handy multiplayer logfile system. Now need to put in useful
144 * applications of it all over the code.
146 * 109 8/07/98 10:17a Allender
147 * use obj_set_flags for setting COULD_BE_PLAYER flag to trap bugs
149 * 108 7/24/98 9:27a Dave
150 * Tidied up endgame sequencing by removing several old flags and
151 * standardizing _all_ endgame stuff with a single function call.
153 * 107 6/13/98 6:01p Hoffoss
154 * Externalized all new (or forgot to be added) strings to all the code.
156 * 106 6/13/98 3:19p Hoffoss
157 * NOX()ed out a bunch of strings that shouldn't be translated.
159 * 105 5/19/98 8:35p Dave
160 * Revamp PXO channel listing system. Send campaign goals/events to
161 * clients for evaluation. Made lock button pressable on all screens.
163 * 104 5/19/98 11:23a Dave
164 * Change mask value for "lock" button.
166 * 103 5/18/98 12:41a Allender
167 * fixed subsystem problems on clients (i.e. not reporting properly on
168 * damage indicator). Fixed ingame join problem with respawns. minor
171 * 102 5/17/98 1:43a Dave
172 * Eradicated chatbox problems. Remove speed match for observers. Put in
173 * help screens for PXO. Fix messaging and end mission privelges. Fixed
174 * team select screen bugs. Misc UI fixes.
176 * 101 5/15/98 5:16p Dave
177 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
178 * status for team vs. team. Put in asserts to check for invalid team vs.
181 * 100 5/10/98 7:06p Dave
182 * Fix endgame sequencing ESC key. Changed how host options warning popups
183 * are done. Fixed pause/message scrollback/options screen problems in mp.
184 * Make sure observer HUD doesn't try to lock weapons.
188 #include "multiteamselect.h"
194 #include "linklist.h"
195 #include "gamesequence.h"
197 #include "multiutil.h"
198 #include "freespace.h"
199 #include "missionscreencommon.h"
200 #include "missionshipchoice.h"
201 #include "missionweaponchoice.h"
202 #include "missionbrief.h"
203 #include "missionparse.h"
204 #include "multimsgs.h"
205 #include "snazzyui.h"
209 #include "multi_endgame.h"
210 #include "alphacolors.h"
213 // ------------------------------------------------------------------------------------------------------
214 // TEAM SELECT DEFINES/VARS
217 // mission screen common data
218 extern int Next_screen;
223 #define MULTI_TS_PALETTE "InterfacePalette"
225 const char *Multi_ts_bitmap_fname[GR_NUM_RESOLUTIONS] = {
226 "TeamSelect", // GR_640
227 "2_TeamSelect" // GR_1024
230 const char *Multi_ts_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
231 "TeamSelect-M", // GR_640
232 "2_TeamSelect-M" // GR_1024
235 // constants for coordinate lookup
236 #define MULTI_TS_X_COORD 0
237 #define MULTI_TS_Y_COORD 1
238 #define MULTI_TS_W_COORD 2
239 #define MULTI_TS_H_COORD 3
241 #define MULTI_TS_NUM_BUTTONS 7
242 #define MULTI_TS_BRIEFING 0 // go to the briefing
243 #define MULTI_TS_SHIP_SELECT 1 // this screen
244 #define MULTI_TS_WEAPON_SELECT 2 // go to the weapon select screen
245 #define MULTI_TS_SHIPS_UP 3 // scroll the ships list up
246 #define MULTI_TS_SHIPS_DOWN 4 // scroll the ships list down
247 #define MULTI_TS_COMMIT 5 // commit
248 #define MULTI_TS_LOCK 6 // lock (free) ship/weapon select
250 ui_button_info Multi_ts_buttons[GR_NUM_RESOLUTIONS][MULTI_TS_NUM_BUTTONS] = {
253 ui_button_info("CB_00", 0, 0, -1, -1, 0),
254 ui_button_info("CB_01", 0, 19, -1, -1, 1),
255 ui_button_info("CB_02", 0, 33, -1, -1, 2),
256 ui_button_info("TSB_03", 0, 302, -1, -1, 3),
257 ui_button_info("TSB_04", 0, 453, -1, -1, 4),
258 ui_button_info("TSB_09", 559, 409, -1, -1, 9),
259 ui_button_info("TSB_34", 601, 344, -1, -1, 50),
261 ui_button_info("CB_00", 7, 3, 37, 7, 0),
262 ui_button_info("CB_01", 7, 19, 37, 23, 1),
263 ui_button_info("CB_02", 7, 35, 37, 39, 2),
264 ui_button_info("TSB_03", 5, 303, -1, -1, 3),
265 ui_button_info("TSB_04", 5, 454, -1, -1, 4),
266 ui_button_info("TSB_09", 571, 425, 572, 413, 9),
267 ui_button_info("TSB_34", 603, 374, 602, 364, 34)
272 ui_button_info("2_CB_00", 12, 5, 59, 12, 0),
273 ui_button_info("2_CB_01", 12, 31, 59, 37, 1),
274 ui_button_info("2_CB_02", 12, 56, 59, 62, 2),
275 ui_button_info("2_TSB_03", 8, 485, -1, -1, 3),
276 ui_button_info("2_TSB_04", 8, 727, -1, -1, 4),
277 ui_button_info("2_TSB_09", 914, 681, 937, 660, 9),
278 ui_button_info("2_TSB_34", 966, 599, 964, 584, 34)
283 // players locked ani graphic
284 #define MULTI_TS_NUM_LOCKED_BITMAPS 3
286 const char *Multi_ts_bmap_names[GR_NUM_RESOLUTIONS][3] = {
298 int Multi_ts_locked_bitmaps[MULTI_TS_NUM_LOCKED_BITMAPS];
301 // snazzy menu regions
302 #define TSWING_0_SHIP_0 10
303 #define TSWING_0_SHIP_1 12
304 #define TSWING_0_SHIP_2 14
305 #define TSWING_0_SHIP_3 16
306 #define TSWING_1_SHIP_0 18
307 #define TSWING_1_SHIP_1 20
308 #define TSWING_1_SHIP_2 22
309 #define TSWING_1_SHIP_3 24
310 #define TSWING_2_SHIP_0 26
311 #define TSWING_2_SHIP_1 28
312 #define TSWING_2_SHIP_2 30
313 #define TSWING_2_SHIP_3 32
315 #define TSWING_0_NAME_0 11
316 #define TSWING_0_NAME_1 13
317 #define TSWING_0_NAME_2 15
318 #define TSWING_0_NAME_3 17
319 #define TSWING_1_NAME_0 19
320 #define TSWING_1_NAME_1 21
321 #define TSWING_1_NAME_2 23
322 #define TSWING_1_NAME_3 25
323 #define TSWING_2_NAME_0 27
324 #define TSWING_2_NAME_1 29
325 #define TSWING_2_NAME_2 31
326 #define TSWING_2_NAME_3 33
328 #define TSWING_LIST_0 5
329 #define TSWING_LIST_1 6
330 #define TSWING_LIST_2 7
331 #define TSWING_LIST_3 8
333 #define MULTI_TS_SLOT_LIST 0
334 #define MULTI_TS_PLAYER_LIST 1
335 #define MULTI_TS_AVAIL_LIST 2
338 #define MULTI_TS_NUM_SNAZZY_REGIONS 28
341 int Multi_ts_inited = 0;
342 int Multi_ts_snazzy_regions;
343 ubyte *Multi_ts_mask_data;
344 int Multi_ts_mask_w, Multi_ts_mask_h;
345 MENU_REGION Multi_ts_region[MULTI_TS_NUM_SNAZZY_REGIONS];
346 UI_WINDOW Multi_ts_window;
349 #define MULTI_TS_NUM_SHIP_SLOTS_TEAM 4 // # of ship slots in team v team
350 #define MULTI_TS_FLAG_NONE -2 // never has any ships
351 #define MULTI_TS_FLAG_EMPTY -1 // currently empty
352 const char *Multi_ts_slot_names[MULTI_TS_NUM_SHIP_SLOTS] = { //
353 "alpha 1", "alpha 2", "alpha 3", "alpha 4",
354 "beta 1", "beta 2", "beta 3", "beta 4",
355 "gamma 1", "gamma 2", "gamma 3", "gamma 4"
357 const char *Multi_ts_slot_team_names[MULTI_TS_MAX_TEAMS][MULTI_TS_NUM_SHIP_SLOTS_TEAM] = {
358 {"alpha 1", "alpha 2", "alpha 3", "alpha 4"},
359 {"zeta 1", "zeta 2", "zeta 3", "zeta 4"}
362 static int Multi_ts_slot_icon_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][2] = { // x,y
413 static int Multi_ts_slot_text_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][3] = { // x,y,width
415 {112,330,181-112}, // GR_640
416 {187,517,181-112} // GR_1024
419 {74,377,143-74}, // GR_640
420 {126,592,143-74} // GR_1024
423 {149,377,218-149},// GR_640
424 {248,592,218-149} // GR_1024
427 {112,424,181-112},// GR_640
428 {187,667,181-112} // GR_1024
431 {274,330,343-274},// GR_640
432 {446,517,343-274} // GR_1024
435 {236,377,305-236},// GR_640
436 {385,592,305-236} // GR_1024
439 {311,377,380-311},// GR_640
440 {507,592,380-311} // GR_1024
443 {274,424,343-274},// GR_640
444 {446,667,343-274} // GR_1024
447 {437,330,506-437},// GR_640
448 {707,517,506-437} // GR_1024
451 {399,377,468-399},// GR_640
452 {646,592,468-399} // GR_1024
455 {474,377,543-474},// GR_640
456 {768,592,543-474} // GR_1024
459 {437,424,506-437},// GR_640
460 {707,667,506-437} // GR_1024
464 // avail ship list data
465 #define MULTI_TS_AVAIL_MAX_DISPLAY 4
466 static int Multi_ts_avail_coords[MULTI_TS_AVAIL_MAX_DISPLAY][GR_NUM_RESOLUTIONS][2] = { // x,y coords
484 int Multi_ts_avail_start = 0; // starting index of where we will display the available ships
485 int Multi_ts_avail_count = 0; // the # of available ship classes
487 // ship information stuff
488 #define MULTI_TS_SHIP_INFO_MAX_LINE_LEN 150
489 #define MULTI_TS_SHIP_INFO_MAX_LINES 10
490 #define MULTI_TS_SHIP_INFO_MAX_TEXT (MULTI_TS_SHIP_INFO_MAX_LINE_LEN * MULTI_TS_SHIP_INFO_MAX_LINES)
492 static int Multi_ts_ship_info_coords[GR_NUM_RESOLUTIONS][3] = {
501 char Multi_ts_ship_info_lines[MULTI_TS_SHIP_INFO_MAX_LINES][MULTI_TS_SHIP_INFO_MAX_LINE_LEN];
502 char Multi_ts_ship_info_text[MULTI_TS_SHIP_INFO_MAX_TEXT];
503 int Multi_ts_ship_info_line_count;
506 static int Multi_ts_status_coords[GR_NUM_RESOLUTIONS][3] = {
515 int Multi_ts_status_bar_mode = 0;
517 // carried icon information
518 int Multi_ts_carried_flag = 0;
519 int Multi_ts_clicked_flag = 0;
520 int Multi_ts_clicked_x,Multi_ts_clicked_y;
521 int Multi_ts_carried_ship_class;
522 int Multi_ts_carried_from_type = 0;
523 int Multi_ts_carried_from_index = 0;
525 // selected ship types (for informational purposes)
526 int Multi_ts_select_type = -1;
527 int Multi_ts_select_index = -1;
528 int Multi_ts_select_ship_class = -1;
530 // per-frame mouse hotspot vars
531 int Multi_ts_hotspot_type = -1;
532 int Multi_ts_hotspot_index = -1;
535 #define TS_GRAB_FROM_LIST 0
536 #define TS_SWAP_LIST_SLOT 1
537 #define TS_SWAP_SLOT_SLOT 2
538 #define TS_DUMP_TO_LIST 3
539 #define TS_SWAP_PLAYER_PLAYER 4
540 #define TS_MOVE_PLAYER 5
543 #define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
544 #define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team
547 #define MULTI_TS_FLAG_NONE -2 // slot is _always_ empty
548 #define MULTI_TS_FLAG_EMPTY -1 // flag is temporarily empty
549 typedef struct ts_team_data {
550 int multi_ts_objnum[MULTI_TS_NUM_SHIP_SLOTS]; // objnums for all slots in this team
551 net_player *multi_ts_player[MULTI_TS_NUM_SHIP_SLOTS]; // net players corresponding to the same slots
552 int multi_ts_flag[MULTI_TS_NUM_SHIP_SLOTS]; // flags indicating the "status" of a slot
553 int multi_players_locked; // are the players locked into place
555 ts_team_data Multi_ts_team[MULTI_TS_MAX_TEAMS]; // data for all teams
557 // deleted ship objnums
558 int Multi_ts_deleted_objnums[MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
559 int Multi_ts_num_deleted;
563 // ------------------------------------------------------------------------------------------------------
564 // TEAM SELECT FORWARD DECLARATIONS
567 // check for button presses
568 void multi_ts_check_buttons();
570 // act on a button press
571 void multi_ts_button_pressed(int n);
573 // initialize all screen data, etc
574 void multi_ts_init_graphics();
576 // blit all of the icons representing all wings
577 void multi_ts_blit_wings();
579 // blit all of the player callsigns under the correct ships
580 void multi_ts_blit_wing_callsigns();
582 // blit the ships on the avail list
583 void multi_ts_blit_avail_ships();
585 // initialize the snazzy menu stuff for dragging ships,players around
586 void multi_ts_init_snazzy();
588 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
589 int multi_ts_region_type(int region);
591 // convert the region num to a ship slot index
592 int multi_ts_slot_index(int region);
594 // convert the region num to an avail list index
595 int multi_ts_avail_index(int region);
597 // convert the region num to a player slot index
598 int multi_ts_player_index(int region);
600 // blit the status bar
601 void multi_ts_blit_status_bar();
603 // assign the correct players to the correct slots
604 void multi_ts_init_players();
606 // assign the correct objnums to the correct slots
607 void multi_ts_init_objnums();
609 // assign the correct flags to the correct slots
610 void multi_ts_init_flags();
612 // get the proper team and slot index for the given ship name
613 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index);
615 // handle an available ship scroll down button press
616 void multi_ts_avail_scroll_down();
618 // handle an available ship scroll up button press
619 void multi_ts_avail_scroll_up();
621 // handle all mouse events (clicking, dragging, and dropping)
622 void multi_ts_handle_mouse();
624 // can the specified player perform the action he is attempting
625 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index = -1);
627 // determine the kind of drag and drop operation this is
628 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index = -1);
630 // swap two player positions
631 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index = -1);
634 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index = -1);
636 // get the ship class of the current index in the avail list or -1 if none exists
637 int multi_ts_get_avail_ship_class(int index);
639 // blit the currently carried icon (if any)
640 void multi_ts_blit_carried_icon();
642 // if the (console) player is allowed to grab a player slot at this point
643 int multi_ts_can_grab_player(int slot_index,int player_index = -1);
645 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
646 int multi_ts_slot_bmap_num(int slot_index);
648 // blit any active ship information text
649 void multi_ts_blit_ship_info();
651 // select the given slot and setup any information, etc
652 void multi_ts_select_ship();
654 // is it ok for this player to commit
655 int multi_ts_ok_to_commit();
657 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
658 int multi_ts_avail_bmap_num(int slot_index);
660 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
661 void multi_ts_set_status_bar_mode(int m);
663 // check to see that no illegal ship settings have occurred
664 void multi_ts_check_errors();
666 // ------------------------------------------------------------------------------------------------------
667 // TEAM SELECT FUNCTIONS
670 // initialize the team select screen (always call, even when switching between weapon select, etc)
673 // if we haven't initialized at all yet, then do it
674 if(!Multi_ts_inited){
675 multi_ts_init_graphics();
679 // use the common interface palette
680 multi_common_set_palette();
682 // set the interface palette
684 common_set_interface_palette(MULTI_TS_PALETTE);
687 Net_player->state = NETPLAYER_STATE_SHIP_SELECT;
689 Current_screen = ON_SHIP_SELECT;
692 // initialize all critical internal data structures
693 void multi_ts_common_init()
697 // reset timestamps here. they seem to get hosed by the loadinh of the mission file
698 multi_reset_timestamps();
700 // saying "not allowed to mess with ships"
701 Multi_ts_status_bar_mode = 0;
703 // intialize ship info stuff
704 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
705 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
706 Multi_ts_ship_info_line_count = 0;
708 // initialize carried icon information
709 Multi_ts_carried_flag = 0;
710 Multi_ts_clicked_flag = 0;
711 Multi_ts_clicked_x = 0;
712 Multi_ts_clicked_y = 0;
713 Multi_ts_carried_ship_class = -1;
714 Multi_ts_carried_from_type = 0;
715 Multi_ts_carried_from_index = 0;
717 // selected slot information (should be default player ship)
718 if(!MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
719 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
720 Multi_ts_select_index = Net_player->p_info.ship_index;
722 // select this ship and setup his info
723 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
724 multi_ts_select_ship();
726 Multi_ts_select_type = -1;
727 Multi_ts_select_index = -1;
729 // no ship class selected for information purposes
730 Multi_ts_select_ship_class = -1;
733 // deleted ship information
734 memset(Multi_ts_deleted_objnums,0,sizeof(int) * MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS);
735 Multi_ts_num_deleted = 0;
737 // mouse hotspot information
738 Multi_ts_hotspot_type = -1;
739 Multi_ts_hotspot_index = -1;
741 // initialize avail ship list data
742 Multi_ts_avail_start = 0;
744 // load the locked button bitmaps bitmaps
745 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
746 Multi_ts_locked_bitmaps[idx] = -1;
747 Multi_ts_locked_bitmaps[idx] = bm_load(Multi_ts_bmap_names[gr_screen.res][idx]);
750 // blast the team data clean
751 memset(Multi_ts_team,0,sizeof(ts_team_data) * MULTI_TS_MAX_TEAMS);
753 // assign the correct players to the correct slots
754 multi_ts_init_players();
756 // assign the correct objnums to the correct slots
757 multi_ts_init_objnums();
759 // sync the interface as normal
760 multi_ts_sync_interface();
763 // do frame for team select
766 int k = chatbox_process();
767 k = Multi_ts_window.process(k);
769 // process any keypresses
772 gamesnd_play_iface(SND_USER_SELECT);
773 multi_quit_game(PROMPT_ALL);
776 // cycle to the weapon select screen
778 gamesnd_play_iface(SND_USER_SELECT);
779 Next_screen = ON_WEAPON_SELECT;
780 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
783 case SDLK_RETURN|KEY_CTRLED:
784 multi_ts_commit_pressed();
788 // check any button presses
789 multi_ts_check_buttons();
791 // handle all mouse related events
792 multi_ts_handle_mouse();
795 multi_ts_check_errors();
797 // draw the background, etc
799 GR_MAYBE_CLEAR_RES(Multi_ts_bitmap);
800 if(Multi_ts_bitmap != -1){
801 gr_set_bitmap(Multi_ts_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
804 Multi_ts_window.draw();
807 multi_ts_blit_wings();
809 // blit all callsigns
810 multi_ts_blit_wing_callsigns();
812 // blit the ships on the available list
813 multi_ts_blit_avail_ships();
815 // force draw the ship select button
816 Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button.draw_forced(2);
818 // force draw the "locked" button if necessary
819 if(multi_ts_is_locked()){
820 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(2);
822 if( ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) ||
823 ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST)) ){
824 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(0);
826 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw();
830 // blit any active ship information
831 multi_ts_blit_ship_info();
833 // blit the status bar
834 multi_ts_blit_status_bar();
836 // render the chatbox
840 Multi_ts_window.draw_tooltip();
842 // display the status of the voice system
843 multi_common_voice_display_status();
845 // blit any carried icons
846 multi_ts_blit_carried_icon();
852 // close the team select screen (always call, even when switching between weapon select, etc)
853 void multi_ts_close()
857 if(!Multi_ts_inited){
863 // shut down the snazzy menu
866 // unload any bitmaps
867 if(!bm_unload(Multi_ts_bitmap)){
868 nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ts_bitmap_fname[gr_screen.res]));
870 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
871 if(Multi_ts_locked_bitmaps[idx] != -1){
872 bm_release(Multi_ts_locked_bitmaps[idx]);
873 Multi_ts_locked_bitmaps[idx] = -1;
877 // destroy the UI_WINDOW
878 Multi_ts_window.destroy();
881 common_free_interface_palette();
885 // is the given slot disabled for the specified player
886 int multi_ts_disabled_slot(int slot_num, int player_index)
890 // get the appropriate net player
891 if(player_index == -1){
894 pl = &Net_players[player_index];
897 // if the player is an observer, its _always_ disabled
898 if(pl->flags & NETINFO_FLAG_OBSERVER){
902 // if the flag for this team isn't set to "free" we can't do anything
903 if(!Multi_ts_team[pl->p_info.team].multi_players_locked){
907 // if the "leaders" only flag is set
908 if(Netgame.options.flags & MSO_FLAG_SS_LEADERS){
909 // in a team vs. team situation
910 if(Netgame.type_flags & NG_TYPE_TEAM){
911 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
915 // in a non team vs. team situation
917 if(pl->flags & NETINFO_FLAG_GAME_HOST){
922 // in a team vs. team situation
923 if(Netgame.type_flags & NG_TYPE_TEAM){
924 // if i'm the team captain I can mess with my own ships as well as those of the ai ships on my team
925 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
926 if((Multi_ts_team[pl->p_info.team].multi_ts_player[slot_num] != NULL) && (Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[slot_num]].flags & OF_PLAYER_SHIP) && (slot_num != pl->p_info.ship_index)){
933 // in a non team vs. team situation
935 // if we're the host, we can our own ship and ai ships
936 if(pl->flags & NETINFO_FLAG_GAME_HOST){
937 // can't grab player ships
938 if((Multi_ts_team[pl->p_info.team].multi_ts_player[slot_num] != NULL) && (Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[slot_num]].flags & OF_PLAYER_SHIP) && (slot_num != pl->p_info.ship_index)){
946 // if this is our slot, then we can grab it
947 if(slot_num == pl->p_info.ship_index){
955 // is the given slot disabled for the specified player, _and_ it is his ship as well
956 int multi_ts_disabled_high_slot(int slot_index,int player_index)
960 // get the appropriate net player
961 if(player_index == -1){
964 pl = &Net_players[player_index];
967 // if this is disabled for him and its also _his_ slot
968 if(multi_ts_disabled_slot(slot_index,player_index) && !Multi_ts_team[pl->p_info.team].multi_players_locked && (slot_index == pl->p_info.ship_index)){
975 // resynch all display/interface elements based upon all the ship/weapon pool values
976 void multi_ts_sync_interface()
980 // item 1 - determine how many ship types are available in the ship pool
981 Multi_ts_avail_count = 0;
982 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
983 if(Ss_pool[idx] > 0){
984 Multi_ts_avail_count++;
988 // item 2 - make sure our local Multi_ts_slot_flag array is up to date
989 multi_ts_init_flags();
991 // item 3 - set/unset any necessary flags in underlying ship select data structures
992 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
993 switch(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx]){
994 case MULTI_TS_FLAG_EMPTY :
995 ss_make_slot_empty(idx);
997 case MULTI_TS_FLAG_NONE :
1000 ss_make_slot_full(idx);
1005 // item 4 - reset the locked/unlocked status of all ships in the weapon select screen
1006 ss_recalc_multiplayer_slots();
1009 void multi_ts_assign_players_all()
1011 int idx,team_index,slot_index,found,player_count,shipnum;
1012 char name_lookup[100];
1015 // set all player ship indices to -1
1016 for(idx=0;idx<MAX_PLAYERS;idx++){
1017 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1018 Net_players[idx].p_info.ship_index = -1;
1022 // merge the created object list with the actual object list so we have all available ships
1023 obj_merge_created_list();
1025 // get the # of players currently in the game
1026 player_count = multi_num_players();
1028 // always assign the host to Alpha 1 (or Zeta 1 in team vs. team - as appropriate)
1029 memset(name_lookup,0,100);
1030 if(Netgame.type_flags & NG_TYPE_TEAM){
1031 switch(Netgame.host->p_info.team){
1033 SDL_strlcpy(name_lookup, NOX("alpha 1"), sizeof(name_lookup));
1036 SDL_strlcpy(name_lookup, NOX("zeta 1"), sizeof(name_lookup));
1040 SDL_strlcpy(name_lookup, NOX("alpha 1"), sizeof(name_lookup));
1042 shipnum = ship_name_lookup(name_lookup);
1044 // if we couldn't find the ship for the host
1046 // Netgame.flags |= NG_FLAG_QUITTING;
1047 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1051 multi_ts_get_team_and_slot(Ships[shipnum].ship_name,&team_index,&slot_index);
1052 multi_assign_player_ship(NET_PLAYER_INDEX(Netgame.host),&Objects[Ships[shipnum].objnum],Ships[shipnum].ship_info_index);
1053 Netgame.host->p_info.ship_index = slot_index;
1054 SDL_assert(Netgame.host->p_info.ship_index >= 0);
1055 Netgame.host->p_info.ship_class = Ships[shipnum].ship_info_index;
1056 Netgame.host->player->objnum = Ships[shipnum].objnum;
1058 // for each netplayer, try and find a ship
1059 objp = GET_FIRST(&obj_used_list);
1060 while(objp != END_OF_LIST(&obj_used_list)){
1061 // find a valid player ship - ignoring the ship which was assigned to the host
1062 if((objp->flags & OF_PLAYER_SHIP) && SDL_strcasecmp(Ships[objp->instance].ship_name,name_lookup)){
1063 // determine what team and slot this ship is
1064 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1065 SDL_assert((team_index != -1) && (slot_index != -1));
1067 // in a team vs. team situation
1068 if(Netgame.type_flags & NG_TYPE_TEAM){
1069 // find a player on this team who needs a ship
1071 for(idx=0;idx<MAX_PLAYERS;idx++){
1072 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1) && (Net_players[idx].p_info.team == team_index)){
1078 // in a non team vs. team situation
1080 // find any player on this who needs a ship
1082 for(idx=0;idx<MAX_PLAYERS;idx++){
1083 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1)){
1090 // if we found a player
1092 multi_assign_player_ship(idx,objp,Ships[objp->instance].ship_info_index);
1093 Net_players[idx].p_info.ship_index = slot_index;
1094 SDL_assert(Net_players[idx].p_info.ship_index >= 0);
1095 Net_players[idx].p_info.ship_class = Ships[objp->instance].ship_info_index;
1096 Net_players[idx].player->objnum = OBJ_INDEX(objp);
1098 // decrement the player count
1101 objp->flags &= ~OF_PLAYER_SHIP;
1102 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1105 // if we've assigned all players, we're done
1106 if(player_count <= 0){
1111 // move to the next item
1112 objp = GET_NEXT(objp);
1115 // go through and change any ships marked as player ships to be COULD_BE_PLAYER
1116 if ( objp != END_OF_LIST(&obj_used_list) ) {
1117 for ( objp = GET_NEXT(objp); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1118 if ( objp->flags & OF_PLAYER_SHIP ){
1119 objp->flags &= ~OF_PLAYER_SHIP;
1120 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1125 if(Game_mode & GM_STANDALONE_SERVER){
1127 Net_player->player->objnum = -1;
1130 // check to make sure all players were assigned correctly
1131 for(idx=0;idx<MAX_PLAYERS;idx++){
1132 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
1133 // if this guy never got assigned a player ship, there's a mission problem
1134 if(Net_players[idx].p_info.ship_index == -1){
1135 // Netgame.flags |= NG_FLAG_QUITTING;
1136 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1143 // delete ships which have been removed from the game, tidy things
1144 void multi_ts_create_wings()
1148 // the standalone never went through this screen so he should never call this function!
1149 // the standalone and all other clients will have this equivalent function performed whey they receieve
1150 // the post_sync_data_packet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1151 SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
1153 // check status of all ships and delete or change ship type as necessary
1154 Multi_ts_num_deleted = 0;
1155 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1156 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1157 // otherwise if there's a valid ship in this spot
1158 if(Multi_ts_team[idx].multi_ts_flag[s_idx] >= 0){
1161 // set the ship type appropriately
1162 SDL_assert(Wss_slots_teams[idx][s_idx].ship_class >= 0);
1164 objnum = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1165 change_ship_type(Objects[objnum].instance,Wss_slots_teams[idx][s_idx].ship_class);
1167 // set the ship weapons correctly
1168 wl_update_ship_weapons(objnum,&Wss_slots_teams[idx][s_idx]);
1170 // assign ts_index of the ship to point to the proper Wss_slots slot
1171 Ships[Objects[objnum].instance].ts_index = s_idx;
1172 } else if(Multi_ts_team[idx].multi_ts_flag[s_idx] == MULTI_TS_FLAG_EMPTY){
1173 SDL_assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] >= 0);
1175 // mark the object as having been deleted
1176 Multi_ts_deleted_objnums[Multi_ts_num_deleted] = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1179 ship_add_exited_ship( &Ships[Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance], SEF_PLAYER_DELETED );
1180 obj_delete(Multi_ts_deleted_objnums[Multi_ts_num_deleted]);
1181 ship_wing_cleanup(Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance,&Wings[Ships[Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].instance].wingnum]);
1183 // increment the # of ships deleted
1184 Multi_ts_num_deleted++;
1190 // do any necessary processing for players who have left the game
1191 void multi_ts_handle_player_drop()
1196 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1197 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1198 // if we found him, clear his player slot and set his object back to being OF_COULD_BE_PLAYER
1199 if((Multi_ts_team[idx].multi_ts_player[s_idx] != NULL) && !MULTI_CONNECTED((*Multi_ts_team[idx].multi_ts_player[s_idx]))){
1200 SDL_assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1);
1201 Multi_ts_team[idx].multi_ts_player[s_idx] = NULL;
1202 Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags &= ~(OF_PLAYER_SHIP);
1203 obj_set_flags( &Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]], Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags | OF_COULD_BE_PLAYER);
1209 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
1210 void multi_ts_set_status_bar_mode(int m)
1212 Multi_ts_status_bar_mode = m;
1215 // blit the proper "locked" button - used for weapon select and briefing screens
1216 void multi_ts_blit_locked_button()
1218 // if we're locked down and we have a valid bitmap
1219 if((Multi_ts_team[Net_player->p_info.team].multi_players_locked) && (Multi_ts_locked_bitmaps[2] != -1)){
1220 gr_set_bitmap(Multi_ts_locked_bitmaps[2], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1221 gr_bitmap(Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1223 // draw as "not locked" if possible
1224 else if(Multi_ts_locked_bitmaps[0] != -1){
1225 gr_set_bitmap(Multi_ts_locked_bitmaps[0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1226 gr_bitmap( Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1230 // the "lock" button has been pressed
1231 void multi_ts_lock_pressed()
1233 // do nothing if the button has already been pressed
1234 if(multi_ts_is_locked()){
1235 gamesnd_play_iface(SND_GENERAL_FAIL);
1239 if(Netgame.type_flags & NG_TYPE_TEAM){
1240 SDL_assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
1242 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1244 gamesnd_play_iface(SND_USER_SELECT);
1246 // send a final player slot update packet
1247 send_pslot_update_packet(Net_player->p_info.team,TS_CODE_LOCK_TEAM,-1);
1248 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
1250 // sync interface stuff
1251 multi_ts_set_status_bar_mode(1);
1252 multi_ts_sync_interface();
1253 ss_recalc_multiplayer_slots();
1255 // disable this button now
1256 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1260 int multi_ts_is_locked()
1262 return Multi_ts_team[Net_player->p_info.team].multi_players_locked;
1265 // show a popup saying "only host and team captains can modify, etc, etc"
1266 void multi_ts_maybe_host_only_popup()
1269 // if this is because the "host modifies" option is set
1270 if((Netgame.options.flags & MSO_FLAG_SS_LEADERS) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1271 multi_ts_host_only_popup();
1274 if(Netgame.type == NG_TYPE_TEAM){
1275 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only team captains may modify ships and weapons in this game");
1277 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only the host may modify ships and weapons in this game");
1283 // ------------------------------------------------------------------------------------------------------
1284 // TEAM SELECT FORWARD DEFINITIONS
1287 // check for button presses
1288 void multi_ts_check_buttons()
1291 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1292 // we only really need to check for one button pressed at a time, so we can break after
1294 if(Multi_ts_buttons[gr_screen.res][idx].button.pressed()){
1295 multi_ts_button_pressed(idx);
1301 // act on a button press
1302 void multi_ts_button_pressed(int n)
1305 // back to the briefing screen
1306 case MULTI_TS_BRIEFING :
1307 gamesnd_play_iface(SND_USER_SELECT);
1308 Next_screen = ON_BRIEFING_SELECT;
1309 gameseq_post_event( GS_EVENT_START_BRIEFING );
1311 // already on this screen
1312 case MULTI_TS_SHIP_SELECT:
1313 gamesnd_play_iface(SND_GENERAL_FAIL);
1315 // back to the weapon select screen
1316 case MULTI_TS_WEAPON_SELECT:
1317 gamesnd_play_iface(SND_USER_SELECT);
1318 Next_screen = ON_WEAPON_SELECT;
1319 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
1321 // scroll the available ships list down
1322 case MULTI_TS_SHIPS_DOWN:
1323 multi_ts_avail_scroll_down();
1325 // scroll the available ships list up
1326 case MULTI_TS_SHIPS_UP:
1327 multi_ts_avail_scroll_up();
1329 // free ship/weapon select
1331 SDL_assert(Game_mode & GM_MULTIPLAYER);
1332 // the "lock" button has been pressed
1333 multi_ts_lock_pressed();
1335 // disable the button if it is now locked
1336 if(multi_ts_is_locked()){
1337 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1341 case MULTI_TS_COMMIT :
1342 multi_ts_commit_pressed();
1345 gamesnd_play_iface(SND_GENERAL_FAIL);
1350 // initialize all screen data, etc
1351 void multi_ts_init_graphics()
1355 // create the interface window
1356 Multi_ts_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
1357 Multi_ts_window.set_mask_bmap(Multi_ts_bitmap_mask_fname[gr_screen.res]);
1359 // load the background bitmap
1360 Multi_ts_bitmap = bm_load(Multi_ts_bitmap_fname[gr_screen.res]);
1361 if(Multi_ts_bitmap < 0){
1362 // we failed to load the bitmap - this is very bad
1366 // create the interface buttons
1367 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1368 // create the object
1369 if((idx == MULTI_TS_SHIPS_UP) || (idx == MULTI_TS_SHIPS_DOWN)){
1370 Multi_ts_buttons[gr_screen.res][idx].button.create(&Multi_ts_window, "", Multi_ts_buttons[gr_screen.res][idx].x, Multi_ts_buttons[gr_screen.res][idx].y, 1, 1, 1, 1);
1372 Multi_ts_buttons[gr_screen.res][idx].button.create(&Multi_ts_window, "", Multi_ts_buttons[gr_screen.res][idx].x, Multi_ts_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
1375 // set the sound to play when highlighted
1376 Multi_ts_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1378 // set the ani for the button
1379 Multi_ts_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ts_buttons[gr_screen.res][idx].filename);
1382 Multi_ts_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ts_buttons[gr_screen.res][idx].hotspot);
1387 Multi_ts_window.add_XSTR("Briefing", 765, Multi_ts_buttons[gr_screen.res][MULTI_TS_BRIEFING].xt, Multi_ts_buttons[gr_screen.res][MULTI_TS_BRIEFING].yt, &Multi_ts_buttons[gr_screen.res][MULTI_TS_BRIEFING].button, UI_XSTR_COLOR_GREEN);
1388 Multi_ts_window.add_XSTR("Ship Selection", 1067, Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].xt, Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].yt, &Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button, UI_XSTR_COLOR_GREEN);
1389 Multi_ts_window.add_XSTR("Weapon Loadout", 1068, Multi_ts_buttons[gr_screen.res][MULTI_TS_WEAPON_SELECT].xt, Multi_ts_buttons[gr_screen.res][MULTI_TS_WEAPON_SELECT].yt, &Multi_ts_buttons[gr_screen.res][MULTI_TS_WEAPON_SELECT].button, UI_XSTR_COLOR_GREEN);
1390 Multi_ts_window.add_XSTR("Commit", 1062, Multi_ts_buttons[gr_screen.res][MULTI_TS_COMMIT].xt, Multi_ts_buttons[gr_screen.res][MULTI_TS_COMMIT].yt, &Multi_ts_buttons[gr_screen.res][MULTI_TS_COMMIT].button, UI_XSTR_COLOR_PINK);
1391 Multi_ts_window.add_XSTR("Lock", 1270, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].xt, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].yt, &Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button, UI_XSTR_COLOR_GREEN);
1394 // Multi_ts_window.add_XSTR("Help", 928, Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].xt, Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].yt, &Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].button, UI_XSTR_COLOR_GREEN);
1395 // Multi_ts_window.add_XSTR("Options", 1036, Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].xt, Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].yt, &Multi_ts_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].button, UI_XSTR_COLOR_GREEN);
1399 // make the ship scrolling lists
1401 // if we're not the host of the game (or a tema captain in team vs. team mode), disable the lock button
1402 if (Netgame.type_flags & NG_TYPE_TEAM) {
1403 if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1404 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1407 if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1408 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1412 // initialize the snazzy menu stuff (for grabbing ships, names, etc)
1413 multi_ts_init_snazzy();
1415 // create the chatbox (again, should not be necessary at this point)
1418 // sync the interface as normal
1419 multi_ts_sync_interface();
1422 // blit all of the icons representing all wings
1423 void multi_ts_blit_wings()
1427 // blit them all blindly for now
1428 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1429 // if this ship doesn't exist, then continue
1430 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1434 // otherwise blit the ship icon or the "empty" icon
1435 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY){
1436 ss_blit_ship_icon(Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_X_COORD],Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_Y_COORD],-1,0);
1438 ss_blit_ship_icon(Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_X_COORD],Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_Y_COORD],Wss_slots[idx].ship_class,multi_ts_slot_bmap_num(idx));
1440 // if this is a team vs team game, and the slot is occupised by a team captain, put a c there
1441 if((Netgame.type_flags & NG_TYPE_TEAM) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1442 gr_set_color_fast(&Color_bright);
1443 gr_string(Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_X_COORD] - 5,Multi_ts_slot_icon_coords[idx][gr_screen.res][MULTI_TS_Y_COORD] - 5,XSTR("C",737)); // [[ Team captain ]]
1449 // blit all of the player callsigns under the correct ships
1450 void multi_ts_blit_wing_callsigns()
1453 char callsign[CALLSIGN_LEN+2];
1456 // blit them all blindly for now
1457 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1458 // if this ship doesn't exist, then continue
1459 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1463 // if there is a player in the slot
1464 if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
1465 // make sure the string fits
1466 SDL_strlcpy(callsign, Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->player->callsign, sizeof(callsign));
1468 // determine if this is a locked AI ship
1469 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
1470 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
1471 SDL_strlcpy(callsign, NOX("<"), sizeof(callsign));
1472 SDL_strlcat(callsign, XSTR("AI", 738), sizeof(callsign)); // [[ Artificial Intellegence ]]
1473 SDL_strlcat(callsign, NOX(">"), sizeof(callsign));
1475 SDL_strlcpy(callsign, XSTR("AI", 738), sizeof(callsign)); // [[ Artificial Intellegence ]]
1479 gr_force_fit_string(callsign, CALLSIGN_LEN, Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD]);
1481 // get the final length
1482 gr_get_string_size(&callsign_w, NULL, callsign);
1485 if((Multi_ts_hotspot_type == MULTI_TS_PLAYER_LIST) && (Multi_ts_hotspot_index == idx) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL)){
1486 gr_set_color_fast(&Color_text_active_hi);
1488 gr_set_color_fast(&Color_normal);
1490 gr_string(Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_X_COORD] + ((Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD] - callsign_w)/2),Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_Y_COORD],callsign);
1494 // blit the ships on the avail list
1495 void multi_ts_blit_avail_ships()
1497 int display_count,ship_count,idx;
1500 // blit the availability of all ship counts
1503 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
1504 if(Ss_pool[idx] > 0){
1505 // if our starting display index is after this, then skip it
1506 if(ship_count < Multi_ts_avail_start){
1510 ss_blit_ship_icon(Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_X_COORD],Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_Y_COORD],idx,multi_ts_avail_bmap_num(display_count));
1512 // blit the ship count available
1513 SDL_snprintf(count,sizeof(count),"%d",Ss_pool[idx]);
1514 gr_set_color_fast(&Color_normal);
1515 gr_string(Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_X_COORD] - 20,Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_Y_COORD],count);
1517 // increment the counts
1523 // if we've reached the max amount we can display, then stop
1524 if(display_count >= MULTI_TS_AVAIL_MAX_DISPLAY){
1530 // initialize the snazzy menu stuff for dragging ships,players around
1531 void multi_ts_init_snazzy()
1533 // initialize the snazzy menu
1537 Multi_ts_snazzy_regions = 0;
1538 memset(Multi_ts_region,0,sizeof(MENU_REGION) * MULTI_TS_NUM_SNAZZY_REGIONS);
1540 // get a pointer to the mask bitmap data
1541 Multi_ts_mask_data = (ubyte*)Multi_ts_window.get_mask_data(&Multi_ts_mask_w, &Multi_ts_mask_h);
1543 // add the wing slots information
1544 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_0, 0);
1545 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_1, 0);
1546 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_2, 0);
1547 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_3, 0);
1548 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_0, 0);
1549 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_1, 0);
1550 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_2, 0);
1551 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_3, 0);
1552 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_0, 0);
1553 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_1, 0);
1554 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_2, 0);
1555 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_3, 0);
1557 // add the name slots information
1558 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_0, 0);
1559 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_1, 0);
1560 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_2, 0);
1561 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_3, 0);
1562 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_0, 0);
1563 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_1, 0);
1564 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_2, 0);
1565 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_3, 0);
1566 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_0, 0);
1567 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_1, 0);
1568 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_2, 0);
1569 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_3, 0);
1571 // add the available ships region
1572 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_0, 0);
1573 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_1, 0);
1574 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_2, 0);
1575 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_3, 0);
1578 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
1579 int multi_ts_region_type(int region)
1581 if((region == TSWING_0_SHIP_0) || (region == TSWING_0_SHIP_1) || (region == TSWING_0_SHIP_2) || (region == TSWING_0_SHIP_3) ||
1582 (region == TSWING_1_SHIP_0) || (region == TSWING_1_SHIP_1) || (region == TSWING_1_SHIP_2) || (region == TSWING_1_SHIP_3) ||
1583 (region == TSWING_2_SHIP_0) || (region == TSWING_2_SHIP_1) || (region == TSWING_2_SHIP_2) || (region == TSWING_2_SHIP_3) ){
1584 return MULTI_TS_SLOT_LIST;
1587 if((region == TSWING_0_NAME_0) || (region == TSWING_0_NAME_1) || (region == TSWING_0_NAME_2) || (region == TSWING_0_NAME_3) ||
1588 (region == TSWING_1_NAME_0) || (region == TSWING_1_NAME_1) || (region == TSWING_1_NAME_2) || (region == TSWING_1_NAME_3) ||
1589 (region == TSWING_2_NAME_0) || (region == TSWING_2_NAME_1) || (region == TSWING_2_NAME_2) || (region == TSWING_2_NAME_3) ){
1590 return MULTI_TS_PLAYER_LIST;
1593 if((region == TSWING_LIST_0) || (region == TSWING_LIST_1) || (region == TSWING_LIST_2) || (region == TSWING_LIST_3)){
1594 return MULTI_TS_AVAIL_LIST;
1600 // convert the region num to a ship slot index
1601 int multi_ts_slot_index(int region)
1604 case TSWING_0_SHIP_0:
1606 case TSWING_0_SHIP_1:
1608 case TSWING_0_SHIP_2:
1610 case TSWING_0_SHIP_3:
1612 case TSWING_1_SHIP_0:
1614 case TSWING_1_SHIP_1:
1616 case TSWING_1_SHIP_2:
1618 case TSWING_1_SHIP_3:
1620 case TSWING_2_SHIP_0:
1622 case TSWING_2_SHIP_1:
1624 case TSWING_2_SHIP_2:
1626 case TSWING_2_SHIP_3:
1633 // convert the region num to an avail list index (starting from absolute 0)
1634 int multi_ts_avail_index(int region)
1650 // convert the region num to a player slot index
1651 int multi_ts_player_index(int region)
1654 case TSWING_0_NAME_0:
1656 case TSWING_0_NAME_1:
1658 case TSWING_0_NAME_2:
1660 case TSWING_0_NAME_3:
1662 case TSWING_1_NAME_0:
1664 case TSWING_1_NAME_1:
1666 case TSWING_1_NAME_2:
1668 case TSWING_1_NAME_3:
1670 case TSWING_2_NAME_0:
1672 case TSWING_2_NAME_1:
1674 case TSWING_2_NAME_2:
1676 case TSWING_2_NAME_3:
1683 // blit any active ship information text
1684 void multi_ts_blit_ship_info()
1690 // if we don't have a valid ship selected, do nothing
1691 if(Multi_ts_select_ship_class == -1){
1695 // get the ship class
1696 sip = &Ship_info[Multi_ts_select_ship_class];
1699 y_start = Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_Y_COORD];
1703 // blit the ship class (name)
1704 gr_set_color_fast(&Color_normal);
1705 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Class",739));
1706 if(strlen(sip->name)){
1707 gr_set_color_fast(&Color_bright);
1708 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->name);
1712 // blit the ship type
1713 gr_set_color_fast(&Color_normal);
1714 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Type",740));
1715 if((sip->type_str != NULL) && strlen(sip->type_str)){
1716 gr_set_color_fast(&Color_bright);
1717 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->type_str);
1721 // blit the ship length
1722 gr_set_color_fast(&Color_normal);
1723 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Length",741));
1724 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1725 gr_set_color_fast(&Color_bright);
1726 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->ship_length);
1730 // blit the max velocity
1731 gr_set_color_fast(&Color_normal);
1732 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Max Velocity",742));
1733 SDL_snprintf(str,sizeof(str),XSTR("%d m/s",743),(int)sip->max_vel.xyz.z);
1734 gr_set_color_fast(&Color_bright);
1735 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,str);
1738 // blit the maneuverability
1739 gr_set_color_fast(&Color_normal);
1740 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Maneuverability",744));
1741 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1742 gr_set_color_fast(&Color_bright);
1743 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->maneuverability_str);
1748 gr_set_color_fast(&Color_normal);
1749 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Armor",745));
1750 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1751 gr_set_color_fast(&Color_bright);
1752 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->armor_str);
1756 // blit the gun mounts
1757 gr_set_color_fast(&Color_normal);
1758 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Gun Mounts",746));
1759 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1760 gr_set_color_fast(&Color_bright);
1761 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->gun_mounts);
1765 // blit the missile banke
1766 gr_set_color_fast(&Color_normal);
1767 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Missile Banks",747));
1768 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1769 gr_set_color_fast(&Color_bright);
1770 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->missile_banks);
1774 // blit the manufacturer
1775 gr_set_color_fast(&Color_normal);
1776 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Manufacturer",748));
1777 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1778 gr_set_color_fast(&Color_bright);
1779 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->manufacturer_str);
1783 // blit the _short_ text description
1785 SDL_assert(Multi_ts_ship_info_line_count < 3);
1786 gr_set_color_fast(&Color_normal);
1787 for(idx=0;idx<Multi_ts_ship_info_line_count;idx++){
1788 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, Multi_ts_ship_info_lines[idx]);
1795 // blit the status bar
1796 void multi_ts_blit_status_bar()
1802 // mode specific text
1803 switch(Multi_ts_status_bar_mode){
1805 SDL_strlcpy(text, XSTR("Ships/Weapons Locked", 749), sizeof(text));
1809 SDL_strlcpy(text, XSTR("Ships/Weapons Are Now Free", 750), sizeof(text));
1814 // if we should be blitting
1816 gr_get_string_size(&text_w,NULL,text);
1817 gr_set_color_fast(&Color_bright_blue);
1818 gr_string(Multi_ts_status_coords[gr_screen.res][MULTI_TS_X_COORD] + ((Multi_ts_status_coords[gr_screen.res][MULTI_TS_W_COORD] - text_w)/2),Multi_ts_status_coords[gr_screen.res][MULTI_TS_Y_COORD],text);
1822 // assign the correct players to the correct slots
1823 void multi_ts_init_players()
1827 // if i'm an observer, i have no ship
1828 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1829 Net_player->p_info.ship_index = -1;
1832 // initialize all players and observer
1833 for(idx=0;idx<MAX_PLAYERS;idx++){
1834 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1835 if(MULTI_OBSERVER(Net_players[idx])){
1836 Net_players[idx].p_info.ship_index = -1;
1838 Multi_ts_team[Net_players[idx].p_info.team].multi_ts_player[Net_players[idx].p_info.ship_index] = &Net_players[idx];
1844 // assign the correct objnums to the correct slots
1845 void multi_ts_init_objnums()
1847 int idx,s_idx,team_index,slot_index;
1850 // zero out the indices
1851 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1852 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1853 Multi_ts_team[idx].multi_ts_objnum[s_idx] = -1;
1857 // set all the objnums
1858 objp = GET_FIRST(&obj_used_list);
1859 while(objp != END_OF_LIST(&obj_used_list)){
1860 // if its a ship, get its slot index (if any)
1861 if(objp->type == OBJ_SHIP){
1862 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1863 if((slot_index != -1) && (team_index != -1)){
1864 Multi_ts_team[team_index].multi_ts_objnum[slot_index] = Ships[objp->instance].objnum;
1868 objp = GET_NEXT(objp);
1872 // get the proper team and slot index for the given ship name
1873 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index)
1877 // set the return values to default values
1881 // if we're in team vs. team mode
1882 if(Netgame.type_flags & NG_TYPE_TEAM){
1883 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1884 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1885 if(!SDL_strcasecmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
1887 *slot_index = s_idx;
1893 // if we're _not_ in team vs. team mode
1895 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1896 if(!SDL_strcasecmp(ship_name,Multi_ts_slot_names[idx])){
1905 // function to return the shipname of the ship in the slot designated by the team and slot
1907 const char *multi_ts_get_shipname( int team, int slot_index )
1909 if ( Netgame.type_flags & NG_TYPE_TEAM ) {
1910 SDL_assert( (team >= 0) && (team < MULTI_TS_MAX_TEAMS) );
1911 return Multi_ts_slot_team_names[team][slot_index];
1913 SDL_assert( team == 0 );
1914 return Multi_ts_slot_names[slot_index];
1918 // assign the correct flags to the correct slots
1919 void multi_ts_init_flags()
1923 // zero out the flags
1924 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1925 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1926 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_NONE;
1930 // in a team vs. team situation
1931 if(Netgame.type_flags & NG_TYPE_TEAM){
1932 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1933 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1934 // if the there is an objnum here but no ship class, we know its currently empty
1935 if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class == -1)){
1936 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_EMPTY;
1937 } else if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class != -1)){
1938 Multi_ts_team[idx].multi_ts_flag[s_idx] = Wss_slots_teams[idx][s_idx].ship_class;
1943 // in a non team vs. team situation
1945 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1946 // if the there is an objnum here but no ship class, we know its currently empty
1947 if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class == -1)){
1948 Multi_ts_team[0].multi_ts_flag[idx] = MULTI_TS_FLAG_EMPTY;
1949 } else if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class != -1)){
1950 Multi_ts_team[0].multi_ts_flag[idx] = Wss_slots[idx].ship_class;
1956 // handle an available ship scroll down button press
1957 void multi_ts_avail_scroll_down()
1959 if((Multi_ts_avail_count - Multi_ts_avail_start) > MULTI_TS_AVAIL_MAX_DISPLAY){
1960 gamesnd_play_iface(SND_USER_SELECT);
1961 Multi_ts_avail_start++;
1963 gamesnd_play_iface(SND_GENERAL_FAIL);
1967 // handle an available ship scroll up button press
1968 void multi_ts_avail_scroll_up()
1970 if(Multi_ts_avail_start > 0){
1971 gamesnd_play_iface(SND_USER_SELECT);
1972 Multi_ts_avail_start--;
1974 gamesnd_play_iface(SND_GENERAL_FAIL);
1978 // handle all mouse events (clicking, dragging, and dropping)
1979 void multi_ts_handle_mouse()
1981 int snazzy_region,snazzy_action;
1982 int region_type,region_index,region_empty;
1983 int mouse_x,mouse_y,ship_class;
1985 // get the mouse coords
1986 mouse_get_pos(&mouse_x,&mouse_y);
1988 // do frame for the snazzy menu
1989 snazzy_region = snazzy_menu_do(Multi_ts_mask_data, Multi_ts_mask_w, Multi_ts_mask_h, Multi_ts_snazzy_regions, Multi_ts_region, &snazzy_action, 0);
1995 if(snazzy_region != -1){
1996 region_type = multi_ts_region_type(snazzy_region);
1997 SDL_assert(region_type != -1);
1999 // determine what type of region the mouse is over and the appropriate index
2000 switch(region_type){
2001 case MULTI_TS_AVAIL_LIST:
2002 region_index = multi_ts_avail_index(snazzy_region);
2003 ship_class = multi_ts_get_avail_ship_class(region_index);
2005 if(ship_class == -1){
2008 region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1;
2011 case MULTI_TS_SLOT_LIST:
2012 region_index = multi_ts_slot_index(snazzy_region);
2013 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] >= 0) ? 0 : 1;
2015 ship_class = Wss_slots[region_index].ship_class;
2018 case MULTI_TS_PLAYER_LIST:
2019 region_index = multi_ts_player_index(snazzy_region);
2020 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL) ? 0 : 1;
2025 // maybe play a "highlight" sound
2026 switch(region_type){
2027 case MULTI_TS_PLAYER_LIST:
2028 if((Multi_ts_hotspot_index != region_index) && (region_index >= 0) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL)){
2029 gamesnd_play_iface(SND_USER_SELECT);
2034 // set the current frame mouse hotspot vars
2035 Multi_ts_hotspot_type = region_type;
2036 Multi_ts_hotspot_index = region_index;
2038 // if we currently have clicked on something and have just released it
2039 if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2040 Multi_ts_clicked_flag = 0;
2043 // if we're currently not carrying anything and the user has clicked
2044 if(!Multi_ts_carried_flag && !Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && !region_empty){
2045 // set the "clicked" flag
2046 Multi_ts_clicked_flag = 1;
2048 // check to see if he clicked on a ship type and highlight if necessary
2049 switch(region_type){
2050 // selected a ship in the wing slots
2051 case MULTI_TS_SLOT_LIST:
2052 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
2053 Multi_ts_select_index = region_index;
2054 multi_ts_select_ship();
2057 // selected a ship on the avail list
2058 case MULTI_TS_AVAIL_LIST:
2059 Multi_ts_select_type = MULTI_TS_AVAIL_LIST;
2060 Multi_ts_select_index = region_index;
2061 multi_ts_select_ship();
2064 // selected something else - unselect
2066 Multi_ts_select_type = -1;
2067 Multi_ts_select_index = -1;
2068 Multi_ts_select_ship_class = -1;
2072 Multi_ts_clicked_x = mouse_x;
2073 Multi_ts_clicked_y = mouse_y;
2076 // if we had something clicked and have started dragging it
2077 if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && ((Multi_ts_clicked_x != mouse_x) || (Multi_ts_clicked_y != mouse_y))){
2078 // if this player is an observer, he shouldn't be able to do jack
2079 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2083 // first we check for illegal conditions (any case where he cannot grab what he is attempting to grab)
2084 switch(region_type){
2085 case MULTI_TS_AVAIL_LIST :
2086 // if players are not yet locked, can't grab ships
2087 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2095 case MULTI_TS_SLOT_LIST:
2096 // if players are not yet locked, can't grab ships
2097 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2101 if(multi_ts_disabled_slot(region_index)){
2102 multi_ts_maybe_host_only_popup();
2105 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] < 0){
2109 case MULTI_TS_PLAYER_LIST:
2110 if(!multi_ts_can_grab_player(region_index)){
2117 Multi_ts_clicked_flag = 0;
2118 Multi_ts_carried_flag = 1;
2120 // set up the carried icon here
2121 Multi_ts_carried_from_type = region_type;
2122 Multi_ts_carried_from_index = region_index;
2123 Multi_ts_carried_ship_class = ship_class;
2126 // if we were carrying something but have dropped it
2127 if(Multi_ts_carried_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2128 Multi_ts_carried_flag = 0;
2129 Multi_ts_clicked_flag = 0;
2131 // if we're not allowed to drop onto this slot
2132 if((region_type == MULTI_TS_SLOT_LIST) && multi_ts_disabled_slot(region_index)){
2133 multi_ts_maybe_host_only_popup();
2136 // if we're over some kind of valid region, apply
2137 multi_ts_drop(Multi_ts_carried_from_type,Multi_ts_carried_from_index,region_type,region_index,Multi_ts_carried_ship_class);
2141 // can the specified player perform the action he is attempting
2142 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2148 // get the appropriate player
2149 if(player_index == -1){
2152 pl = &Net_players[player_index];
2155 // get the operation type
2156 op_type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2158 // if either of the indices are bogus, then bail
2159 if((from_index == -1) || (to_index == -1)){
2164 case TS_GRAB_FROM_LIST:
2165 // if there are no more of this ship class, its no go
2166 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2170 // if he's not allowed to touch the wing slot
2171 if(multi_ts_disabled_slot(to_index,player_index)){
2175 // if the slot he's trying to drop it on is "permanently" empty
2176 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2181 case TS_SWAP_LIST_SLOT:
2182 // if there are no more of this ship class, its no go
2183 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2187 // if he's not allowed to touch the wing slot
2188 if(multi_ts_disabled_slot(to_index,player_index)){
2192 // if the slot we're trying to move to is invalid, then do nothing
2193 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2197 // if the slot he's trying to drop it on is "permanently" empty
2198 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2203 case TS_SWAP_SLOT_SLOT:
2204 // if he's not allowed to touch one of the slots, its no go
2205 if(multi_ts_disabled_slot(from_index,player_index) || multi_ts_disabled_slot(to_index,player_index)){
2209 // if the slot we're taking from is invalid
2210 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2214 // if the slot he's trying to drop it on is "permanently" empty
2215 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2220 case TS_DUMP_TO_LIST:
2221 // if he's not allowed to be touching the slot to begin with, it no go
2222 if(multi_ts_disabled_slot(from_index,player_index)){
2226 // if the slot we're trying to move to is invalid, then do nothing
2227 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2232 case TS_SWAP_PLAYER_PLAYER:
2233 // if his team is already locked, he cannot do this
2234 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2238 // if there isn't a player at one of the positions
2239 if((Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL) || (Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL)){
2243 // if this is not a player ship type object
2244 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2245 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2246 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2251 if(Netgame.type_flags & NG_TYPE_TEAM){
2252 // if he's not the team captain, he cannot do this
2253 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2257 // if he's not the host, he cannot do this
2258 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2264 case TS_MOVE_PLAYER:
2265 // if his team is already locked, he cannot do this
2266 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2270 // if there isn't a player at the _from_
2271 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL){
2275 // if there is no ship at the _to_ location
2276 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] < 0){
2280 // if this is not a player ship type object
2281 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2282 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2283 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2288 if(Netgame.type_flags & NG_TYPE_TEAM){
2289 // if he's not the team captain, he cannot do this
2290 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2294 // if he's not the host, he cannot do this
2295 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2309 // determine the kind of drag and drop operation this is
2310 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)
2314 // get the appropriate player
2315 if(player_index == -1){
2318 pl = &Net_players[player_index];
2322 // came from the ship avail list
2323 case MULTI_TS_AVAIL_LIST :
2325 if(to_type == MULTI_TS_AVAIL_LIST){
2329 // if placing it on a slot
2330 if(to_type == MULTI_TS_SLOT_LIST){
2331 if(Wss_slots_teams[pl->p_info.team][to_index].ship_class == -1){
2332 return TS_GRAB_FROM_LIST;
2334 return TS_SWAP_LIST_SLOT;
2339 // came from the ship slots
2340 case MULTI_TS_SLOT_LIST :
2341 if(to_type == MULTI_TS_SLOT_LIST){
2342 return TS_SWAP_SLOT_SLOT;
2344 if(to_type == MULTI_TS_AVAIL_LIST){
2345 return TS_DUMP_TO_LIST;
2349 // came from the player lists
2350 case MULTI_TS_PLAYER_LIST :
2351 if(to_type == MULTI_TS_PLAYER_LIST){
2352 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL){
2353 return TS_MOVE_PLAYER;
2355 return TS_SWAP_PLAYER_PLAYER;
2364 void multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2366 int size,update,sound;
2367 ubyte wss_data[MAX_PACKET_SIZE-20];
2370 // determine what kind of operation this is
2371 int type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2373 // get the proper net player
2374 if(player_index == -1){
2377 pl = &Net_players[player_index];
2380 // set the proper pool pointers
2381 ss_set_team_pointers(pl->p_info.team);
2385 case TS_SWAP_SLOT_SLOT :
2386 nprintf(("Network","Apply swap slot slot %d %d\n",from_index,to_index));
2387 update = ss_swap_slot_slot(from_index,to_index,&sound);
2389 case TS_DUMP_TO_LIST :
2390 nprintf(("Network","Apply dump to list %d %d\n",from_index,to_index));
2391 update = ss_dump_to_list(from_index,ship_class,&sound);
2393 case TS_SWAP_LIST_SLOT :
2394 nprintf(("Network","Apply swap list slot %d %d\n",from_index,to_index));
2395 update = ss_swap_list_slot(ship_class,to_index,&sound);
2397 case TS_GRAB_FROM_LIST :
2398 nprintf(("Network","Apply grab from list %d %d\n",from_index,to_index));
2399 update = ss_grab_from_list(ship_class,to_index,&sound);
2401 case TS_SWAP_PLAYER_PLAYER :
2402 nprintf(("Network","Apply swap player player %d %d\n",from_index,to_index));
2403 update = multi_ts_swap_player_player(from_index,to_index,&sound,player_index);
2405 case TS_MOVE_PLAYER :
2406 nprintf(("Network","Apply move player %d %d\n",from_index,to_index));
2407 update = multi_ts_move_player(from_index,to_index,&sound,player_index);
2414 // if we're the host, send an update to all players
2415 if ( MULTIPLAYER_HOST ) {
2416 // send the correct type of update
2417 if(type == TS_SWAP_PLAYER_PLAYER){
2419 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound, player_index);
2420 send_wss_update_packet(pl->p_info.team,wss_data, size);
2422 // send a player slot update packet as well, so ship class information, etc is kept correct
2423 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,-1);
2426 // if the player index == -1, it means the action was done locally - so play a sound
2427 if((player_index == -1) && (sound != -1)){
2428 gamesnd_play_iface(sound);
2432 // sync the interface screen up ourselves, if necessary
2433 if(Net_player->p_info.team == pl->p_info.team){
2434 multi_ts_sync_interface();
2437 // make sure all flags are set properly for all teams
2438 multi_ts_init_flags();
2441 // set the proper pool pointers
2442 ss_set_team_pointers(Net_player->p_info.team);
2445 // drop a carried icon
2446 void multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2448 // if I'm the host, apply immediately
2449 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2450 // if this is a legal operation
2451 if(multi_ts_can_perform(from_type,from_index,to_type,to_index,ship_class,player_index)){
2452 multi_ts_apply(from_type,from_index,to_type,to_index,ship_class,player_index);
2454 nprintf(("Network","Could not apply operation!\n"));
2457 // otherwise send a request to the host
2459 send_wss_request_packet(Net_player->player_id, from_type, from_index, to_type, to_index, -1, ship_class, WSS_SHIP_SELECT);
2463 // swap two player positions
2464 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index)
2466 net_player *pl,*temp;
2468 // get the proper player pointer
2469 if(player_index == -1){
2472 pl = &Net_players[player_index];
2476 temp = Multi_ts_team[pl->p_info.team].multi_ts_player[to_index];
2477 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2478 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = temp;
2480 // update netplayer information if necessary
2481 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2482 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2483 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_class = Wss_slots_teams[pl->p_info.team][from_index].ship_class;
2485 multi_assign_player_ship(NET_PLAYER_INDEX(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]),&Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]],Wss_slots_teams[pl->p_info.team][from_index].ship_class);
2487 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2488 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2489 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_class = Wss_slots_teams[pl->p_info.team][to_index].ship_class;
2491 multi_assign_player_ship(NET_PLAYER_INDEX(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]),&Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]],Wss_slots_teams[pl->p_info.team][to_index].ship_class);
2494 // update ship flags
2495 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2496 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2497 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2498 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2500 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2501 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2502 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2503 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2506 // recalcalate which slots are locked/unlocked, etc
2507 ss_recalc_multiplayer_slots();
2509 // send an update packet to all players
2510 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2511 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2512 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2515 *sound = SND_ICON_DROP;
2521 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index)
2525 // get the proper player pointer
2526 if(player_index == -1){
2529 pl = &Net_players[player_index];
2533 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2534 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = NULL;
2536 // update netplayer information if necessary
2537 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2538 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2539 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_class = Wss_slots_teams[pl->p_info.team][from_index].ship_class;
2541 multi_assign_player_ship(NET_PLAYER_INDEX(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]),&Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]],Wss_slots_teams[pl->p_info.team][from_index].ship_class);
2543 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2544 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2545 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_class = Wss_slots_teams[pl->p_info.team][to_index].ship_class;
2547 multi_assign_player_ship(NET_PLAYER_INDEX(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]),&Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]],Wss_slots_teams[pl->p_info.team][to_index].ship_class);
2550 // update ship flags
2551 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2552 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2553 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2554 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2556 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2557 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2558 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2559 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2562 // recalcalate which slots are locked/unlocked, etc
2563 ss_recalc_multiplayer_slots();
2565 // send an update packet to all players
2566 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2567 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2568 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2571 *sound = SND_ICON_DROP;
2576 // get the ship class of the current index in the avail list or -1 if none exists
2577 int multi_ts_get_avail_ship_class(int index)
2579 int ship_count,class_index;
2581 ship_count = index + Multi_ts_avail_start;
2583 while((ship_count >= 0) && (class_index < MAX_SHIP_TYPES)){
2584 if(Ss_pool[class_index] > 0){
2588 if(ship_count >= 0){
2600 // blit the currently carried icon (if any)
2601 void multi_ts_blit_carried_icon()
2604 int offset_x,offset_y,callsign_w;
2605 char callsign[CALLSIGN_LEN+2];
2607 // if we're not carrying anything, then return
2608 if(!Multi_ts_carried_flag){
2612 // get the mouse position
2613 mouse_get_pos(&x,&y);
2615 // if we're carrying an icon of some kind
2616 switch(Multi_ts_carried_from_type){
2617 case MULTI_TS_SLOT_LIST:
2618 offset_x = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2619 offset_y = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2622 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2624 case MULTI_TS_AVAIL_LIST:
2625 offset_x = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2626 offset_y = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2629 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2631 case MULTI_TS_PLAYER_LIST:
2632 // get the final length of the string so we can calculate a valid offset
2633 SDL_strlcpy(callsign, Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->player->callsign, sizeof(callsign));
2634 gr_force_fit_string(callsign,CALLSIGN_LEN,Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD]);
2635 gr_get_string_size(&callsign_w,NULL,callsign);
2637 // calculate the offsets
2638 offset_x = (Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x) + ((Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD] - callsign_w)/2);
2639 offset_y = Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2641 gr_set_color_fast(&Color_normal);
2642 gr_string(x + offset_x,y + offset_y,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->player->callsign);
2649 // if the (console) player is allowed to grab a player slot at this point
2650 int multi_ts_can_grab_player(int slot_index, int player_index)
2654 // get a pointe rto the proper net player
2655 if(player_index == -1){
2658 pl = &Net_players[player_index];
2661 // if the players are locked in any case, he annot grab it
2662 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2666 if(Netgame.type_flags & NG_TYPE_TEAM){
2667 // if he's not the team captain, he cannot do this
2668 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2672 // if he's not the host, he cannot do this
2673 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2678 // if the slot is empty
2679 if(Multi_ts_team[pl->p_info.team].multi_ts_player[slot_index] == NULL){
2686 // get the team # of the given ship
2687 int multi_ts_get_team(char *ship_name)
2691 // lookup through all team ship names
2692 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
2693 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
2694 if(!SDL_strcasecmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
2700 // always on team 0 if not found otherwise
2704 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2705 int multi_ts_avail_bmap_num(int slot_index)
2707 // if this slot has been highlighted for informational purposes
2708 if((Multi_ts_select_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_select_index == slot_index)){
2709 return ICON_FRAME_SELECTED;
2712 // if its otherwise being lit by the mouse
2713 if((Multi_ts_hotspot_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_hotspot_index == slot_index)){
2714 return ICON_FRAME_HOT;
2717 return ICON_FRAME_NORMAL;
2720 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2721 int multi_ts_slot_bmap_num(int slot_index)
2723 // special case - slot is disabled, its my ship and the host hasn't locked the ships yet
2724 if(multi_ts_disabled_high_slot(slot_index)){
2725 return ICON_FRAME_DISABLED_HIGH;
2728 // if this slot is disabled for us, then show it as such
2729 if(multi_ts_disabled_slot(slot_index)){
2730 return ICON_FRAME_DISABLED;
2733 // if this slot has been highlighted for informational purposes
2734 if((Multi_ts_select_type == MULTI_TS_SLOT_LIST) && (Multi_ts_select_index == slot_index)){
2735 return ICON_FRAME_SELECTED;
2738 // if this is our ship, then highlight it as so
2739 if(Net_player->p_info.ship_index == slot_index){
2740 return ICON_FRAME_PLAYER;
2743 // if its otherwise being lit by the mouse
2744 if((Multi_ts_hotspot_type == MULTI_TS_SLOT_LIST) && (Multi_ts_hotspot_index == slot_index)){
2745 return ICON_FRAME_HOT;
2748 // normal unhighlighted frame
2749 return ICON_FRAME_NORMAL;
2752 // select the given slot and setup any information, etc
2753 void multi_ts_select_ship()
2757 int n_chars[MAX_BRIEF_LINES];
2758 char ship_desc[1000];
2759 char *p_str[MAX_BRIEF_LINES];
2763 // blast all current text
2764 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2765 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2767 // get the selected ship class
2768 SDL_assert(Multi_ts_select_index >= 0);
2769 Multi_ts_select_ship_class = -1;
2770 switch(Multi_ts_select_type){
2771 case MULTI_TS_SLOT_LIST:
2772 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
2774 case MULTI_TS_AVAIL_LIST:
2775 Multi_ts_select_ship_class = multi_ts_get_avail_ship_class(Multi_ts_select_index);
2776 // if he has selected an empty slot, don't do anything
2777 if(Multi_ts_select_ship_class < 0){
2782 // should always have one of the 2 above types selected
2787 // split the text info up
2789 SDL_assert(Multi_ts_select_ship_class >= 0);
2790 SDL_assert((Ship_info[Multi_ts_select_ship_class].desc != NULL) && strlen(Ship_info[Multi_ts_select_ship_class].desc));
2792 // strip out newlines
2793 memset(ship_desc,0,1000);
2794 strcpy(ship_desc,Ship_info[Multi_ts_select_ship_class].desc);
2795 token = strtok(ship_desc,"\n");
2797 strcpy(Multi_ts_ship_info_text,token);
2798 while(token != NULL){
2799 token = strtok(NULL,"\n");
2801 strcat(Multi_ts_ship_info_text," ");
2802 strcat(Multi_ts_ship_info_text,token);
2807 if(strlen(Multi_ts_ship_info_text) > 0){
2808 // split the string into multiple lines
2809 n_lines = split_str(Multi_ts_ship_info_text, Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_W_COORD], n_chars, p_str, MULTI_TS_SHIP_INFO_MAX_LINES, 0);
2811 // copy the split up lines into the text lines array
2812 for (idx=0;idx<n_lines;idx++ ) {
2813 SDL_assert(n_chars[idx] < MULTI_TS_SHIP_INFO_MAX_LINE_LEN);
2814 strncpy(Multi_ts_ship_info_lines[idx], p_str[idx], n_chars[idx]);
2815 Multi_ts_ship_info_lines[idx][n_chars[idx]] = 0;
2816 drop_leading_white_space(Multi_ts_ship_info_lines[idx]);
2819 // get the line count
2820 Multi_ts_ship_info_line_count = n_lines;
2822 // set the line count to
2823 Multi_ts_ship_info_line_count = 0;
2828 // handle all details when the commit button is pressed (including possibly reporting errors/popups)
2829 void multi_ts_commit_pressed()
2831 // if my team's slots are still not "locked", we cannot commit unless we're the only player in the game
2832 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2833 if(multi_num_players() != 1){
2834 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("Players have not yet been assigned to their ships",751));
2837 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
2841 // check to see if its not ok for this player to commit
2842 switch(multi_ts_ok_to_commit()){
2843 // yes, it _is_ ok to commit
2845 extern void commit_pressed();
2849 // player has not assigned all necessary ships
2851 gamesnd_play_iface(SND_GENERAL_FAIL);
2852 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("You have not yet assigned all necessary ships",752));
2855 // there are ships without primary weapons
2857 gamesnd_play_iface(SND_GENERAL_FAIL);
2858 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without primary weapons!",753));
2861 // there are ships without secondary weapons
2863 gamesnd_play_iface(SND_GENERAL_FAIL);
2864 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without secondary weapons!",754));
2869 // is it ok for this player to commit
2870 int multi_ts_ok_to_commit()
2873 int primary_ok,secondary_ok;
2875 // if this player is an observer, he can always commit
2876 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2880 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2881 // if this is a player slot this player can modify and it is empty, then he cannot continue
2882 // implies there is never an object in this slot
2883 if((Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2884 // implies player can't touch this slot anyway
2885 !multi_ts_disabled_slot(idx) &&
2886 // implies that there should be a player ship here but there isn't
2887 ((Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL) && (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY)) ){
2891 // if the ship in this slot has a ship which can be a player but has 0 primary or secondary weapons, then he cannot continue
2892 if( (Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2893 ((Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER) ||
2894 (Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP)) &&
2895 !multi_ts_disabled_slot(idx)){
2899 // go through all weapons in the list
2900 for(s_idx=0;s_idx<MAX_WL_WEAPONS;s_idx++){
2901 // if this slot has a weapon with a greater than 0 count, check
2902 if((Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx] >= 0) && (Wss_slots_teams[Net_player->p_info.team][idx].wep_count[s_idx] > 0)){
2903 switch(Weapon_info[Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx]].subtype){
2917 // if we've got both primary and secondary weapons
2918 if(primary_ok && secondary_ok){
2923 // if the ship doesn't have primary weapons
2928 // if the ship doesn't have secondary weapons
2938 // check to see that no illegal ship settings have occurred
2939 void multi_ts_check_errors()
2945 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2946 if(Multi_ts_team[0].multi_ts_objnum[idx] == -1){
2950 shipp = &Ships[Objects[Multi_ts_team[0].multi_ts_objnum[idx]].instance];
2951 SDL_assert((shipp->weapons.current_primary_bank != -1) && (shipp->weapons.current_secondary_bank != -1));
2957 // ------------------------------------------------------------------------------------------------------
2958 // TEAM SELECT PACKET HANDLERS
2961 // send a player slot position update
2962 void send_pslot_update_packet(int team,int code,int sound)
2964 ubyte data[MAX_PACKET_SIZE],stop,val;
2967 int packet_size = 0;
2970 // build the header and add the data
2971 BUILD_HEADER(SLOT_UPDATE);
2981 // add the sound to play
2982 s_sound = (short)sound;
2985 // add data based upon the packet code
2987 case TS_CODE_LOCK_TEAM:
2988 // don't have to do anything
2990 case TS_CODE_PLAYER_UPDATE:
2991 // only the host should ever be doing this
2992 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
2994 // add individual slot data
2995 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
2996 if(Multi_ts_team[team].multi_ts_flag[idx] != MULTI_TS_FLAG_NONE){
3005 // add the ship class
3006 val = (ubyte)Wss_slots_teams[team][idx].ship_class;
3009 // add the objnum we're working with
3010 i_tmp = Multi_ts_team[team].multi_ts_objnum[idx];
3013 // add a byte indicating if a player is here or not
3014 if(Multi_ts_team[team].multi_ts_player[idx] == NULL){
3021 // if there's a player, add his address
3023 ADD_SHORT(Multi_ts_team[team].multi_ts_player[idx]->player_id);
3025 // should also update his p_info settings locally
3026 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_class = Wss_slots_teams[team][idx].ship_class;
3027 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_index = idx;
3030 // add a byte indicating what object flag should be set (0 == ~(OF_COULD_BE_PLAYER | OF_PLAYER_SHIP), 1 == player ship, 2 == could be player ship)
3031 if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER){
3033 } else if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP){
3041 // add a final stop byte
3050 // send the packet to the standalone
3051 if(Net_player->flags & NETINFO_FLAG_AM_MASTER) {
3052 multi_io_send_to_all_reliable(data, packet_size);
3054 multi_io_send_reliable(Net_player, data, packet_size);
3058 // process a player slot position update
3059 void process_pslot_update_packet(ubyte *data, header *hinfo)
3061 int offset = HEADER_LENGTH;
3063 int player_index,idx,team,code,objnum;
3066 ubyte stop,val,slot_num,ship_class;
3068 my_index = Net_player->p_info.ship_index;
3070 // if we're the standalone, then we should be routing this data to all the other clients
3072 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3073 // fill in the address information of where this came from
3074 player_index = find_player_id(hinfo->id);
3075 SDL_assert(player_index != -1);
3086 // get the sound to play
3089 // process the different opcodes
3091 case TS_CODE_LOCK_TEAM:
3093 Multi_ts_team[team].multi_players_locked = 1;
3095 // if this was my team, sync stuff up
3096 if((team == Net_player->p_info.team) && !(Game_mode & GM_STANDALONE_SERVER)){
3097 multi_ts_set_status_bar_mode(1);
3098 multi_ts_sync_interface();
3099 ss_recalc_multiplayer_slots();
3102 // if this is the standalone server, we need to re-route the packet here and there
3103 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3104 // in team vs team mode, only a team captain should ever be sending this
3105 if(Netgame.type_flags & NG_TYPE_TEAM){
3106 SDL_assert(Net_players[player_index].flags & NETINFO_FLAG_TEAM_CAPTAIN);
3108 // in any other mode, it better be coming from the game host
3110 SDL_assert(Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST);
3113 // re-route to all other players
3114 for(idx=0;idx<MAX_PLAYERS;idx++){
3115 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
3116 multi_io_send_reliable(&Net_players[idx], data, offset);
3121 case TS_CODE_PLAYER_UPDATE:
3122 // get the first stop byte
3124 while(stop != 0xff){
3128 // get the ship class
3129 GET_DATA(ship_class);
3134 // flag indicating if a player is in this slot
3137 // look the player up
3138 GET_SHORT(player_id);
3139 player_index = find_player_id(player_id);
3141 // if we couldn't find him
3142 if(player_index == -1){
3143 nprintf(("Network","Couldn't find player for pslot update!\n"));
3144 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3146 // if we found him, assign him to this ship
3148 Net_players[player_index].p_info.ship_class = (int)ship_class;
3149 Net_players[player_index].p_info.ship_index = (int)slot_num;
3150 multi_assign_player_ship(player_index,&Objects[objnum],(int)ship_class);
3153 Multi_ts_team[team].multi_ts_player[slot_num] = &Net_players[player_index];
3155 // if this was me and my ship index changed, update the weapon select screen
3156 if(my_index != Net_player->p_info.ship_index){
3157 wl_reset_selected_slot();
3159 my_index = Net_player->p_info.ship_index;
3163 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3166 // get the ship flag byte
3168 Objects[objnum].flags &= ~(OF_PLAYER_SHIP | OF_COULD_BE_PLAYER);
3171 Objects[objnum].flags |= OF_PLAYER_SHIP;
3174 obj_set_flags( &Objects[objnum], Objects[objnum].flags | OF_COULD_BE_PLAYER );
3178 // get the next stop byte
3181 // if we have a sound we're supposed to play
3182 if((sound != -1) && !(Game_mode & GM_STANDALONE_SERVER) && (gameseq_get_state() == GS_STATE_TEAM_SELECT)){
3183 gamesnd_play_iface(sound);
3186 // if i'm the standalone server, I should rebroadcast this packet
3187 if(Game_mode & GM_STANDALONE_SERVER){
3188 for(idx=0;idx<MAX_PLAYERS;idx++){
3189 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_HOST(Net_players[idx]) && (Net_player != &Net_players[idx])){
3190 multi_io_send_reliable(&Net_players[idx], data, offset);
3198 // recalculate stuff
3199 if(!(Game_mode & GM_STANDALONE_SERVER)){
3200 ss_recalc_multiplayer_slots();