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.7 2004/09/20 01:31:44 theoddone33
21 * Revision 1.6 2004/06/11 01:51:13 tigital
22 * byte-swapping changes for bigendian systems
24 * Revision 1.5 2003/05/25 02:30:43 taylor
27 * Revision 1.4 2002/06/17 06:33:10 relnev
28 * ryan's struct patch for gcc 2.95
30 * Revision 1.3 2002/06/09 04:41:24 relnev
31 * added copyright header
33 * Revision 1.2 2002/05/07 03:16:47 theoddone33
34 * The Great Newline Fix
36 * Revision 1.1.1.1 2002/05/03 03:28:10 root
40 * 27 9/13/99 12:54p Jefff
43 * 26 9/12/99 3:21p Jefff
44 * commit button coord fix in 640
46 * 25 8/05/99 9:57p Jefff
47 * fixed some button wierdness
49 * 24 8/05/99 5:08p Jefff
50 * fixed some location probs
52 * 23 7/28/99 5:34p Dave
53 * Nailed the missing stats bug to the wall. Problem was optimized build
54 * and using GET_DATA() with array elements. BLECH.
56 * 22 7/24/99 6:02p Jefff
57 * Added "lock" text to lock button
59 * 21 5/03/99 8:32p Dave
60 * New version of multi host options screen.
62 * 20 3/25/99 6:36p Neilk
63 * more hires coord fixes
65 * 19 3/25/99 2:44p Neilk
68 * 18 3/23/99 11:56a Neilk
69 * new source safe checkin
71 * 17 3/10/99 6:50p Dave
72 * Changed the way we buffer packets for all clients. Optimized turret
73 * fired packets. Did some weapon firing optimizations.
75 * 16 3/09/99 6:24p Dave
76 * More work on object update revamping. Identified several sources of
77 * unnecessary bandwidth.
79 * 15 2/21/99 6:02p Dave
80 * Fixed standalone WSS packets.
82 * 14 2/11/99 3:08p Dave
83 * PXO refresh button. Very preliminary squad war support.
85 * 13 2/01/99 5:55p Dave
86 * Removed the idea of explicit bitmaps for buttons. Fixed text
87 * highlighting for disabled gadgets.
89 * 12 1/30/99 5:08p Dave
90 * More new hi-res stuff.Support for nice D3D textures.
92 * 11 1/30/99 1:29a Dave
93 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
94 * screen. Fixed beam weapon death messages.
96 * 10 1/29/99 5:07p Dave
97 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
100 * 9 1/13/99 7:19p Neilk
101 * Converted Mission Brief, Barracks, Synch to high res support
103 * 8 12/18/98 1:13a Dave
104 * Rough 1024x768 support for Direct3D. Proper detection and usage through
107 * 7 11/30/98 1:07p Dave
108 * 16 bit conversion, first run.
110 * 6 11/19/98 8:04a Dave
111 * Full support for D3-style reliable sockets. Revamped packet lag/loss
112 * system, made it receiver side and at the lowest possible level.
114 * 5 11/17/98 11:12a Dave
115 * Removed player identification by address. Now assign explicit id #'s.
117 * 4 11/05/98 5:55p Dave
118 * Big pass at reducing #includes
120 * 3 10/13/98 9:29a Dave
121 * Started neatening up freespace.h. Many variables renamed and
122 * reorganized. Added AlphaColors.[h,cpp]
124 * 2 10/07/98 10:53a Dave
127 * 1 10/07/98 10:50a Dave
129 * 112 9/18/98 2:22a Dave
130 * Fixed freespace-side PXO api to correctly handle length 10 id strings.
131 * Fixed team select screen to handle alpha/beta/gamma ships which are not
132 * marked as OF_PLAYER_SHIP
134 * 111 9/17/98 3:08p Dave
135 * PXO to non-pxo game warning popup. Player icon stuff in create and join
136 * game screens. Upped server count refresh time in PXO to 35 secs (from
139 * 110 8/20/98 5:31p Dave
140 * Put in handy multiplayer logfile system. Now need to put in useful
141 * applications of it all over the code.
143 * 109 8/07/98 10:17a Allender
144 * use obj_set_flags for setting COULD_BE_PLAYER flag to trap bugs
146 * 108 7/24/98 9:27a Dave
147 * Tidied up endgame sequencing by removing several old flags and
148 * standardizing _all_ endgame stuff with a single function call.
150 * 107 6/13/98 6:01p Hoffoss
151 * Externalized all new (or forgot to be added) strings to all the code.
153 * 106 6/13/98 3:19p Hoffoss
154 * NOX()ed out a bunch of strings that shouldn't be translated.
156 * 105 5/19/98 8:35p Dave
157 * Revamp PXO channel listing system. Send campaign goals/events to
158 * clients for evaluation. Made lock button pressable on all screens.
160 * 104 5/19/98 11:23a Dave
161 * Change mask value for "lock" button.
163 * 103 5/18/98 12:41a Allender
164 * fixed subsystem problems on clients (i.e. not reporting properly on
165 * damage indicator). Fixed ingame join problem with respawns. minor
168 * 102 5/17/98 1:43a Dave
169 * Eradicated chatbox problems. Remove speed match for observers. Put in
170 * help screens for PXO. Fix messaging and end mission privelges. Fixed
171 * team select screen bugs. Misc UI fixes.
173 * 101 5/15/98 5:16p Dave
174 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
175 * status for team vs. team. Put in asserts to check for invalid team vs.
178 * 100 5/10/98 7:06p Dave
179 * Fix endgame sequencing ESC key. Changed how host options warning popups
180 * are done. Fixed pause/message scrollback/options screen problems in mp.
181 * Make sure observer HUD doesn't try to lock weapons.
185 #include "multiteamselect.h"
191 #include "linklist.h"
192 #include "gamesequence.h"
194 #include "multiutil.h"
195 #include "freespace.h"
196 #include "missionscreencommon.h"
197 #include "missionshipchoice.h"
198 #include "missionweaponchoice.h"
199 #include "missionbrief.h"
200 #include "missionparse.h"
201 #include "multimsgs.h"
202 #include "snazzyui.h"
206 #include "multi_endgame.h"
207 #include "alphacolors.h"
210 // ------------------------------------------------------------------------------------------------------
211 // TEAM SELECT DEFINES/VARS
214 // mission screen common data
215 extern int Next_screen;
220 #define MULTI_TS_PALETTE "InterfacePalette"
222 char *Multi_ts_bitmap_fname[GR_NUM_RESOLUTIONS] = {
223 "TeamSelect", // GR_640
224 "2_TeamSelect" // GR_1024
227 char *Multi_ts_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
228 "TeamSelect-M", // GR_640
229 "2_TeamSelect-M" // GR_1024
232 // constants for coordinate lookup
233 #define MULTI_TS_X_COORD 0
234 #define MULTI_TS_Y_COORD 1
235 #define MULTI_TS_W_COORD 2
236 #define MULTI_TS_H_COORD 3
238 #define MULTI_TS_NUM_BUTTONS 7
239 #define MULTI_TS_BRIEFING 0 // go to the briefing
240 #define MULTI_TS_SHIP_SELECT 1 // this screen
241 #define MULTI_TS_WEAPON_SELECT 2 // go to the weapon select screen
242 #define MULTI_TS_SHIPS_UP 3 // scroll the ships list up
243 #define MULTI_TS_SHIPS_DOWN 4 // scroll the ships list down
244 #define MULTI_TS_COMMIT 5 // commit
245 #define MULTI_TS_LOCK 6 // lock (free) ship/weapon select
247 ui_button_info Multi_ts_buttons[GR_NUM_RESOLUTIONS][MULTI_TS_NUM_BUTTONS] = {
250 ui_button_info("CB_00", 0, 0, -1, -1, 0),
251 ui_button_info("CB_01", 0, 19, -1, -1, 1),
252 ui_button_info("CB_02", 0, 33, -1, -1, 2),
253 ui_button_info("TSB_03", 0, 302, -1, -1, 3),
254 ui_button_info("TSB_04", 0, 453, -1, -1, 4),
255 ui_button_info("TSB_09", 559, 409, -1, -1, 9),
256 ui_button_info("TSB_34", 601, 344, -1, -1, 50),
258 ui_button_info("CB_00", 7, 3, 37, 7, 0),
259 ui_button_info("CB_01", 7, 19, 37, 23, 1),
260 ui_button_info("CB_02", 7, 35, 37, 39, 2),
261 ui_button_info("TSB_03", 5, 303, -1, -1, 3),
262 ui_button_info("TSB_04", 5, 454, -1, -1, 4),
263 ui_button_info("TSB_09", 571, 425, 572, 413, 9),
264 ui_button_info("TSB_34", 603, 374, 602, 364, 34)
269 ui_button_info("2_CB_00", 12, 5, 59, 12, 0),
270 ui_button_info("2_CB_01", 12, 31, 59, 37, 1),
271 ui_button_info("2_CB_02", 12, 56, 59, 62, 2),
272 ui_button_info("2_TSB_03", 8, 485, -1, -1, 3),
273 ui_button_info("2_TSB_04", 8, 727, -1, -1, 4),
274 ui_button_info("2_TSB_09", 914, 681, 937, 660, 9),
275 ui_button_info("2_TSB_34", 966, 599, 964, 584, 34)
280 // players locked ani graphic
281 #define MULTI_TS_NUM_LOCKED_BITMAPS 3
283 char *Multi_ts_bmap_names[GR_NUM_RESOLUTIONS][3] = {
295 int Multi_ts_locked_bitmaps[MULTI_TS_NUM_LOCKED_BITMAPS];
298 // snazzy menu regions
299 #define TSWING_0_SHIP_0 10
300 #define TSWING_0_SHIP_1 12
301 #define TSWING_0_SHIP_2 14
302 #define TSWING_0_SHIP_3 16
303 #define TSWING_1_SHIP_0 18
304 #define TSWING_1_SHIP_1 20
305 #define TSWING_1_SHIP_2 22
306 #define TSWING_1_SHIP_3 24
307 #define TSWING_2_SHIP_0 26
308 #define TSWING_2_SHIP_1 28
309 #define TSWING_2_SHIP_2 30
310 #define TSWING_2_SHIP_3 32
312 #define TSWING_0_NAME_0 11
313 #define TSWING_0_NAME_1 13
314 #define TSWING_0_NAME_2 15
315 #define TSWING_0_NAME_3 17
316 #define TSWING_1_NAME_0 19
317 #define TSWING_1_NAME_1 21
318 #define TSWING_1_NAME_2 23
319 #define TSWING_1_NAME_3 25
320 #define TSWING_2_NAME_0 27
321 #define TSWING_2_NAME_1 29
322 #define TSWING_2_NAME_2 31
323 #define TSWING_2_NAME_3 33
325 #define TSWING_LIST_0 5
326 #define TSWING_LIST_1 6
327 #define TSWING_LIST_2 7
328 #define TSWING_LIST_3 8
330 #define MULTI_TS_SLOT_LIST 0
331 #define MULTI_TS_PLAYER_LIST 1
332 #define MULTI_TS_AVAIL_LIST 2
335 #define MULTI_TS_NUM_SNAZZY_REGIONS 28
338 int Multi_ts_inited = 0;
339 int Multi_ts_snazzy_regions;
340 ubyte *Multi_ts_mask_data;
341 int Multi_ts_mask_w, Multi_ts_mask_h;
342 MENU_REGION Multi_ts_region[MULTI_TS_NUM_SNAZZY_REGIONS];
343 UI_WINDOW Multi_ts_window;
346 #define MULTI_TS_NUM_SHIP_SLOTS_TEAM 4 // # of ship slots in team v team
347 #define MULTI_TS_FLAG_NONE -2 // never has any ships
348 #define MULTI_TS_FLAG_EMPTY -1 // currently empty
349 char *Multi_ts_slot_names[MULTI_TS_NUM_SHIP_SLOTS] = { //
350 "alpha 1", "alpha 2", "alpha 3", "alpha 4",
351 "beta 1", "beta 2", "beta 3", "beta 4",
352 "gamma 1", "gamma 2", "gamma 3", "gamma 4"
354 char *Multi_ts_slot_team_names[MULTI_TS_MAX_TEAMS][MULTI_TS_NUM_SHIP_SLOTS_TEAM] = {
355 {"alpha 1", "alpha 2", "alpha 3", "alpha 4"},
356 {"zeta 1", "zeta 2", "zeta 3", "zeta 4"}
359 static int Multi_ts_slot_icon_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][2] = { // x,y
410 static int Multi_ts_slot_text_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][3] = { // x,y,width
412 {112,330,181-112}, // GR_640
413 {187,517,181-112} // GR_1024
416 {74,377,143-74}, // GR_640
417 {126,592,143-74} // GR_1024
420 {149,377,218-149},// GR_640
421 {248,592,218-149} // GR_1024
424 {112,424,181-112},// GR_640
425 {187,667,181-112} // GR_1024
428 {274,330,343-274},// GR_640
429 {446,517,343-274} // GR_1024
432 {236,377,305-236},// GR_640
433 {385,592,305-236} // GR_1024
436 {311,377,380-311},// GR_640
437 {507,592,380-311} // GR_1024
440 {274,424,343-274},// GR_640
441 {446,667,343-274} // GR_1024
444 {437,330,506-437},// GR_640
445 {707,517,506-437} // GR_1024
448 {399,377,468-399},// GR_640
449 {646,592,468-399} // GR_1024
452 {474,377,543-474},// GR_640
453 {768,592,543-474} // GR_1024
456 {437,424,506-437},// GR_640
457 {707,667,506-437} // GR_1024
461 // avail ship list data
462 #define MULTI_TS_AVAIL_MAX_DISPLAY 4
463 static int Multi_ts_avail_coords[MULTI_TS_AVAIL_MAX_DISPLAY][GR_NUM_RESOLUTIONS][2] = { // x,y coords
481 int Multi_ts_avail_start = 0; // starting index of where we will display the available ships
482 int Multi_ts_avail_count = 0; // the # of available ship classes
484 // ship information stuff
485 #define MULTI_TS_SHIP_INFO_MAX_LINE_LEN 150
486 #define MULTI_TS_SHIP_INFO_MAX_LINES 10
487 #define MULTI_TS_SHIP_INFO_MAX_TEXT (MULTI_TS_SHIP_INFO_MAX_LINE_LEN * MULTI_TS_SHIP_INFO_MAX_LINES)
489 static int Multi_ts_ship_info_coords[GR_NUM_RESOLUTIONS][3] = {
498 char Multi_ts_ship_info_lines[MULTI_TS_SHIP_INFO_MAX_LINES][MULTI_TS_SHIP_INFO_MAX_LINE_LEN];
499 char Multi_ts_ship_info_text[MULTI_TS_SHIP_INFO_MAX_TEXT];
500 int Multi_ts_ship_info_line_count;
503 static int Multi_ts_status_coords[GR_NUM_RESOLUTIONS][3] = {
512 int Multi_ts_status_bar_mode = 0;
514 // carried icon information
515 int Multi_ts_carried_flag = 0;
516 int Multi_ts_clicked_flag = 0;
517 int Multi_ts_clicked_x,Multi_ts_clicked_y;
518 int Multi_ts_carried_ship_class;
519 int Multi_ts_carried_from_type = 0;
520 int Multi_ts_carried_from_index = 0;
522 // selected ship types (for informational purposes)
523 int Multi_ts_select_type = -1;
524 int Multi_ts_select_index = -1;
525 int Multi_ts_select_ship_class = -1;
527 // per-frame mouse hotspot vars
528 int Multi_ts_hotspot_type = -1;
529 int Multi_ts_hotspot_index = -1;
532 #define TS_GRAB_FROM_LIST 0
533 #define TS_SWAP_LIST_SLOT 1
534 #define TS_SWAP_SLOT_SLOT 2
535 #define TS_DUMP_TO_LIST 3
536 #define TS_SWAP_PLAYER_PLAYER 4
537 #define TS_MOVE_PLAYER 5
540 #define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
541 #define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team
544 #define MULTI_TS_FLAG_NONE -2 // slot is _always_ empty
545 #define MULTI_TS_FLAG_EMPTY -1 // flag is temporarily empty
546 typedef struct ts_team_data {
547 int multi_ts_objnum[MULTI_TS_NUM_SHIP_SLOTS]; // objnums for all slots in this team
548 net_player *multi_ts_player[MULTI_TS_NUM_SHIP_SLOTS]; // net players corresponding to the same slots
549 int multi_ts_flag[MULTI_TS_NUM_SHIP_SLOTS]; // flags indicating the "status" of a slot
550 int multi_players_locked; // are the players locked into place
552 ts_team_data Multi_ts_team[MULTI_TS_MAX_TEAMS]; // data for all teams
554 // deleted ship objnums
555 int Multi_ts_deleted_objnums[MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
556 int Multi_ts_num_deleted;
560 // ------------------------------------------------------------------------------------------------------
561 // TEAM SELECT FORWARD DECLARATIONS
564 // check for button presses
565 void multi_ts_check_buttons();
567 // act on a button press
568 void multi_ts_button_pressed(int n);
570 // initialize all screen data, etc
571 void multi_ts_init_graphics();
573 // blit all of the icons representing all wings
574 void multi_ts_blit_wings();
576 // blit all of the player callsigns under the correct ships
577 void multi_ts_blit_wing_callsigns();
579 // blit the ships on the avail list
580 void multi_ts_blit_avail_ships();
582 // initialize the snazzy menu stuff for dragging ships,players around
583 void multi_ts_init_snazzy();
585 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
586 int multi_ts_region_type(int region);
588 // convert the region num to a ship slot index
589 int multi_ts_slot_index(int region);
591 // convert the region num to an avail list index
592 int multi_ts_avail_index(int region);
594 // convert the region num to a player slot index
595 int multi_ts_player_index(int region);
597 // blit the status bar
598 void multi_ts_blit_status_bar();
600 // assign the correct players to the correct slots
601 void multi_ts_init_players();
603 // assign the correct objnums to the correct slots
604 void multi_ts_init_objnums();
606 // assign the correct flags to the correct slots
607 void multi_ts_init_flags();
609 // get the proper team and slot index for the given ship name
610 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index);
612 // handle an available ship scroll down button press
613 void multi_ts_avail_scroll_down();
615 // handle an available ship scroll up button press
616 void multi_ts_avail_scroll_up();
618 // handle all mouse events (clicking, dragging, and dropping)
619 void multi_ts_handle_mouse();
621 // can the specified player perform the action he is attempting
622 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index = -1);
624 // determine the kind of drag and drop operation this is
625 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index = -1);
627 // swap two player positions
628 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index = -1);
631 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index = -1);
633 // get the ship class of the current index in the avail list or -1 if none exists
634 int multi_ts_get_avail_ship_class(int index);
636 // blit the currently carried icon (if any)
637 void multi_ts_blit_carried_icon();
639 // if the (console) player is allowed to grab a player slot at this point
640 int multi_ts_can_grab_player(int slot_index,int player_index = -1);
642 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
643 int multi_ts_slot_bmap_num(int slot_index);
645 // blit any active ship information text
646 void multi_ts_blit_ship_info();
648 // select the given slot and setup any information, etc
649 void multi_ts_select_ship();
651 // is it ok for this player to commit
652 int multi_ts_ok_to_commit();
654 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
655 int multi_ts_avail_bmap_num(int slot_index);
657 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
658 void multi_ts_set_status_bar_mode(int m);
660 // check to see that no illegal ship settings have occurred
661 void multi_ts_check_errors();
663 // ------------------------------------------------------------------------------------------------------
664 // TEAM SELECT FUNCTIONS
667 // initialize the team select screen (always call, even when switching between weapon select, etc)
670 // if we haven't initialized at all yet, then do it
671 if(!Multi_ts_inited){
672 multi_ts_init_graphics();
676 // use the common interface palette
677 multi_common_set_palette();
679 // set the interface palette
681 common_set_interface_palette(MULTI_TS_PALETTE);
684 Net_player->state = NETPLAYER_STATE_SHIP_SELECT;
686 Current_screen = ON_SHIP_SELECT;
689 // initialize all critical internal data structures
690 void multi_ts_common_init()
694 // reset timestamps here. they seem to get hosed by the loadinh of the mission file
695 multi_reset_timestamps();
697 // saying "not allowed to mess with ships"
698 Multi_ts_status_bar_mode = 0;
700 // intialize ship info stuff
701 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
702 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
703 Multi_ts_ship_info_line_count = 0;
705 // initialize carried icon information
706 Multi_ts_carried_flag = 0;
707 Multi_ts_clicked_flag = 0;
708 Multi_ts_clicked_x = 0;
709 Multi_ts_clicked_y = 0;
710 Multi_ts_carried_ship_class = -1;
711 Multi_ts_carried_from_type = 0;
712 Multi_ts_carried_from_index = 0;
714 // selected slot information (should be default player ship)
715 if(!MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
716 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
717 Multi_ts_select_index = Net_player->p_info.ship_index;
719 // select this ship and setup his info
720 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
721 multi_ts_select_ship();
723 Multi_ts_select_type = -1;
724 Multi_ts_select_index = -1;
726 // no ship class selected for information purposes
727 Multi_ts_select_ship_class = -1;
730 // deleted ship information
731 memset(Multi_ts_deleted_objnums,0,sizeof(int) * MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS);
732 Multi_ts_num_deleted = 0;
734 // mouse hotspot information
735 Multi_ts_hotspot_type = -1;
736 Multi_ts_hotspot_index = -1;
738 // initialize avail ship list data
739 Multi_ts_avail_start = 0;
741 // load the locked button bitmaps bitmaps
742 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
743 Multi_ts_locked_bitmaps[idx] = -1;
744 Multi_ts_locked_bitmaps[idx] = bm_load(Multi_ts_bmap_names[gr_screen.res][idx]);
747 // blast the team data clean
748 memset(Multi_ts_team,0,sizeof(ts_team_data) * MULTI_TS_MAX_TEAMS);
750 // assign the correct players to the correct slots
751 multi_ts_init_players();
753 // assign the correct objnums to the correct slots
754 multi_ts_init_objnums();
756 // sync the interface as normal
757 multi_ts_sync_interface();
760 // do frame for team select
763 int k = chatbox_process();
764 k = Multi_ts_window.process(k);
766 // process any keypresses
769 gamesnd_play_iface(SND_USER_SELECT);
770 multi_quit_game(PROMPT_ALL);
773 // cycle to the weapon select screen
775 gamesnd_play_iface(SND_USER_SELECT);
776 Next_screen = ON_WEAPON_SELECT;
777 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
780 case KEY_ENTER|KEY_CTRLED:
781 multi_ts_commit_pressed();
785 // check any button presses
786 multi_ts_check_buttons();
788 // handle all mouse related events
789 multi_ts_handle_mouse();
792 multi_ts_check_errors();
794 // draw the background, etc
796 GR_MAYBE_CLEAR_RES(Multi_ts_bitmap);
797 if(Multi_ts_bitmap != -1){
798 gr_set_bitmap(Multi_ts_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
801 Multi_ts_window.draw();
804 multi_ts_blit_wings();
806 // blit all callsigns
807 multi_ts_blit_wing_callsigns();
809 // blit the ships on the available list
810 multi_ts_blit_avail_ships();
812 // force draw the ship select button
813 Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button.draw_forced(2);
815 // force draw the "locked" button if necessary
816 if(multi_ts_is_locked()){
817 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(2);
819 if( ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) ||
820 ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST)) ){
821 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(0);
823 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw();
827 // blit any active ship information
828 multi_ts_blit_ship_info();
830 // blit the status bar
831 multi_ts_blit_status_bar();
833 // render the chatbox
837 Multi_ts_window.draw_tooltip();
839 // display the status of the voice system
840 multi_common_voice_display_status();
842 // blit any carried icons
843 multi_ts_blit_carried_icon();
849 // close the team select screen (always call, even when switching between weapon select, etc)
850 void multi_ts_close()
854 if(!Multi_ts_inited){
860 // shut down the snazzy menu
863 // unload any bitmaps
864 if(!bm_unload(Multi_ts_bitmap)){
865 nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ts_bitmap_fname[gr_screen.res]));
867 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
868 if(Multi_ts_locked_bitmaps[idx] != -1){
869 bm_release(Multi_ts_locked_bitmaps[idx]);
870 Multi_ts_locked_bitmaps[idx] = -1;
874 // destroy the UI_WINDOW
875 Multi_ts_window.destroy();
878 common_free_interface_palette();
882 // is the given slot disabled for the specified player
883 int multi_ts_disabled_slot(int slot_num, int player_index)
887 // get the appropriate net player
888 if(player_index == -1){
891 pl = &Net_players[player_index];
894 // if the player is an observer, its _always_ disabled
895 if(pl->flags & NETINFO_FLAG_OBSERVER){
899 // if the flag for this team isn't set to "free" we can't do anything
900 if(!Multi_ts_team[pl->p_info.team].multi_players_locked){
904 // if the "leaders" only flag is set
905 if(Netgame.options.flags & MSO_FLAG_SS_LEADERS){
906 // in a team vs. team situation
907 if(Netgame.type_flags & NG_TYPE_TEAM){
908 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
912 // in a non team vs. team situation
914 if(pl->flags & NETINFO_FLAG_GAME_HOST){
919 // in a team vs. team situation
920 if(Netgame.type_flags & NG_TYPE_TEAM){
921 // if i'm the team captain I can mess with my own ships as well as those of the ai ships on my team
922 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
923 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)){
930 // in a non team vs. team situation
932 // if we're the host, we can our own ship and ai ships
933 if(pl->flags & NETINFO_FLAG_GAME_HOST){
934 // can't grab player ships
935 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)){
943 // if this is our slot, then we can grab it
944 if(slot_num == pl->p_info.ship_index){
952 // is the given slot disabled for the specified player, _and_ it is his ship as well
953 int multi_ts_disabled_high_slot(int slot_index,int player_index)
957 // get the appropriate net player
958 if(player_index == -1){
961 pl = &Net_players[player_index];
964 // if this is disabled for him and its also _his_ slot
965 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)){
972 // resynch all display/interface elements based upon all the ship/weapon pool values
973 void multi_ts_sync_interface()
977 // item 1 - determine how many ship types are available in the ship pool
978 Multi_ts_avail_count = 0;
979 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
980 if(Ss_pool[idx] > 0){
981 Multi_ts_avail_count++;
985 // item 2 - make sure our local Multi_ts_slot_flag array is up to date
986 multi_ts_init_flags();
988 // item 3 - set/unset any necessary flags in underlying ship select data structures
989 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
990 switch(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx]){
991 case MULTI_TS_FLAG_EMPTY :
992 ss_make_slot_empty(idx);
994 case MULTI_TS_FLAG_NONE :
997 ss_make_slot_full(idx);
1002 // item 4 - reset the locked/unlocked status of all ships in the weapon select screen
1003 ss_recalc_multiplayer_slots();
1006 void multi_ts_assign_players_all()
1008 int idx,team_index,slot_index,found,player_count,shipnum;
1009 char name_lookup[100];
1012 // set all player ship indices to -1
1013 for(idx=0;idx<MAX_PLAYERS;idx++){
1014 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1015 Net_players[idx].p_info.ship_index = -1;
1019 // merge the created object list with the actual object list so we have all available ships
1020 obj_merge_created_list();
1022 // get the # of players currently in the game
1023 player_count = multi_num_players();
1025 // always assign the host to Alpha 1 (or Zeta 1 in team vs. team - as appropriate)
1026 memset(name_lookup,0,100);
1027 if(Netgame.type_flags & NG_TYPE_TEAM){
1028 switch(Netgame.host->p_info.team){
1030 strcpy(name_lookup,NOX("alpha 1"));
1033 strcpy(name_lookup,NOX("zeta 1"));
1037 strcpy(name_lookup,NOX("alpha 1"));
1039 shipnum = ship_name_lookup(name_lookup);
1041 // if we couldn't find the ship for the host
1043 // Netgame.flags |= NG_FLAG_QUITTING;
1044 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1048 multi_ts_get_team_and_slot(Ships[shipnum].ship_name,&team_index,&slot_index);
1049 multi_assign_player_ship(NET_PLAYER_INDEX(Netgame.host),&Objects[Ships[shipnum].objnum],Ships[shipnum].ship_info_index);
1050 Netgame.host->p_info.ship_index = slot_index;
1051 Assert(Netgame.host->p_info.ship_index >= 0);
1052 Netgame.host->p_info.ship_class = Ships[shipnum].ship_info_index;
1053 Netgame.host->player->objnum = Ships[shipnum].objnum;
1055 // for each netplayer, try and find a ship
1056 objp = GET_FIRST(&obj_used_list);
1057 while(objp != END_OF_LIST(&obj_used_list)){
1058 // find a valid player ship - ignoring the ship which was assigned to the host
1059 if((objp->flags & OF_PLAYER_SHIP) && stricmp(Ships[objp->instance].ship_name,name_lookup)){
1060 // determine what team and slot this ship is
1061 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1062 Assert((team_index != -1) && (slot_index != -1));
1064 // in a team vs. team situation
1065 if(Netgame.type_flags & NG_TYPE_TEAM){
1066 // find a player on this team who needs a ship
1068 for(idx=0;idx<MAX_PLAYERS;idx++){
1069 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)){
1075 // in a non team vs. team situation
1077 // find any player on this who needs a ship
1079 for(idx=0;idx<MAX_PLAYERS;idx++){
1080 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1)){
1087 // if we found a player
1089 multi_assign_player_ship(idx,objp,Ships[objp->instance].ship_info_index);
1090 Net_players[idx].p_info.ship_index = slot_index;
1091 Assert(Net_players[idx].p_info.ship_index >= 0);
1092 Net_players[idx].p_info.ship_class = Ships[objp->instance].ship_info_index;
1093 Net_players[idx].player->objnum = OBJ_INDEX(objp);
1095 // decrement the player count
1098 objp->flags &= ~OF_PLAYER_SHIP;
1099 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1102 // if we've assigned all players, we're done
1103 if(player_count <= 0){
1108 // move to the next item
1109 objp = GET_NEXT(objp);
1112 // go through and change any ships marked as player ships to be COULD_BE_PLAYER
1113 if ( objp != END_OF_LIST(&obj_used_list) ) {
1114 for ( objp = GET_NEXT(objp); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1115 if ( objp->flags & OF_PLAYER_SHIP ){
1116 objp->flags &= ~OF_PLAYER_SHIP;
1117 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1122 if(Game_mode & GM_STANDALONE_SERVER){
1124 Net_player->player->objnum = -1;
1127 // check to make sure all players were assigned correctly
1128 for(idx=0;idx<MAX_PLAYERS;idx++){
1129 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
1130 // if this guy never got assigned a player ship, there's a mission problem
1131 if(Net_players[idx].p_info.ship_index == -1){
1132 // Netgame.flags |= NG_FLAG_QUITTING;
1133 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1140 // delete ships which have been removed from the game, tidy things
1141 void multi_ts_create_wings()
1145 // the standalone never went through this screen so he should never call this function!
1146 // the standalone and all other clients will have this equivalent function performed whey they receieve
1147 // the post_sync_data_packet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1148 Assert(!(Game_mode & GM_STANDALONE_SERVER));
1150 // check status of all ships and delete or change ship type as necessary
1151 Multi_ts_num_deleted = 0;
1152 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1153 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1154 // otherwise if there's a valid ship in this spot
1155 if(Multi_ts_team[idx].multi_ts_flag[s_idx] >= 0){
1158 // set the ship type appropriately
1159 Assert(Wss_slots_teams[idx][s_idx].ship_class >= 0);
1161 objnum = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1162 change_ship_type(Objects[objnum].instance,Wss_slots_teams[idx][s_idx].ship_class);
1164 // set the ship weapons correctly
1165 wl_update_ship_weapons(objnum,&Wss_slots_teams[idx][s_idx]);
1167 // assign ts_index of the ship to point to the proper Wss_slots slot
1168 Ships[Objects[objnum].instance].ts_index = s_idx;
1169 } else if(Multi_ts_team[idx].multi_ts_flag[s_idx] == MULTI_TS_FLAG_EMPTY){
1170 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] >= 0);
1172 // mark the object as having been deleted
1173 Multi_ts_deleted_objnums[Multi_ts_num_deleted] = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1176 ship_add_exited_ship( &Ships[Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance], SEF_PLAYER_DELETED );
1177 obj_delete(Multi_ts_deleted_objnums[Multi_ts_num_deleted]);
1178 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]);
1180 // increment the # of ships deleted
1181 Multi_ts_num_deleted++;
1187 // do any necessary processing for players who have left the game
1188 void multi_ts_handle_player_drop()
1193 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1194 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1195 // if we found him, clear his player slot and set his object back to being OF_COULD_BE_PLAYER
1196 if((Multi_ts_team[idx].multi_ts_player[s_idx] != NULL) && !MULTI_CONNECTED((*Multi_ts_team[idx].multi_ts_player[s_idx]))){
1197 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1);
1198 Multi_ts_team[idx].multi_ts_player[s_idx] = NULL;
1199 Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags &= ~(OF_PLAYER_SHIP);
1200 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);
1206 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
1207 void multi_ts_set_status_bar_mode(int m)
1209 Multi_ts_status_bar_mode = m;
1212 // blit the proper "locked" button - used for weapon select and briefing screens
1213 void multi_ts_blit_locked_button()
1215 // if we're locked down and we have a valid bitmap
1216 if((Multi_ts_team[Net_player->p_info.team].multi_players_locked) && (Multi_ts_locked_bitmaps[2] != -1)){
1217 gr_set_bitmap(Multi_ts_locked_bitmaps[2], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1218 gr_bitmap(Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1220 // draw as "not locked" if possible
1221 else if(Multi_ts_locked_bitmaps[0] != -1){
1222 gr_set_bitmap(Multi_ts_locked_bitmaps[0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1223 gr_bitmap( Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1227 // the "lock" button has been pressed
1228 void multi_ts_lock_pressed()
1230 // do nothing if the button has already been pressed
1231 if(multi_ts_is_locked()){
1232 gamesnd_play_iface(SND_GENERAL_FAIL);
1236 if(Netgame.type_flags & NG_TYPE_TEAM){
1237 Assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
1239 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1241 gamesnd_play_iface(SND_USER_SELECT);
1243 // send a final player slot update packet
1244 send_pslot_update_packet(Net_player->p_info.team,TS_CODE_LOCK_TEAM,-1);
1245 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
1247 // sync interface stuff
1248 multi_ts_set_status_bar_mode(1);
1249 multi_ts_sync_interface();
1250 ss_recalc_multiplayer_slots();
1252 // disable this button now
1253 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1257 int multi_ts_is_locked()
1259 return Multi_ts_team[Net_player->p_info.team].multi_players_locked;
1262 // show a popup saying "only host and team captains can modify, etc, etc"
1263 void multi_ts_maybe_host_only_popup()
1266 // if this is because the "host modifies" option is set
1267 if((Netgame.options.flags & MSO_FLAG_SS_LEADERS) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1268 multi_ts_host_only_popup();
1271 if(Netgame.type == NG_TYPE_TEAM){
1272 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only team captains may modify ships and weapons in this game");
1274 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only the host may modify ships and weapons in this game");
1280 // ------------------------------------------------------------------------------------------------------
1281 // TEAM SELECT FORWARD DEFINITIONS
1284 // check for button presses
1285 void multi_ts_check_buttons()
1288 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1289 // we only really need to check for one button pressed at a time, so we can break after
1291 if(Multi_ts_buttons[gr_screen.res][idx].button.pressed()){
1292 multi_ts_button_pressed(idx);
1298 // act on a button press
1299 void multi_ts_button_pressed(int n)
1302 // back to the briefing screen
1303 case MULTI_TS_BRIEFING :
1304 gamesnd_play_iface(SND_USER_SELECT);
1305 Next_screen = ON_BRIEFING_SELECT;
1306 gameseq_post_event( GS_EVENT_START_BRIEFING );
1308 // already on this screen
1309 case MULTI_TS_SHIP_SELECT:
1310 gamesnd_play_iface(SND_GENERAL_FAIL);
1312 // back to the weapon select screen
1313 case MULTI_TS_WEAPON_SELECT:
1314 gamesnd_play_iface(SND_USER_SELECT);
1315 Next_screen = ON_WEAPON_SELECT;
1316 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
1318 // scroll the available ships list down
1319 case MULTI_TS_SHIPS_DOWN:
1320 multi_ts_avail_scroll_down();
1322 // scroll the available ships list up
1323 case MULTI_TS_SHIPS_UP:
1324 multi_ts_avail_scroll_up();
1326 // free ship/weapon select
1328 Assert(Game_mode & GM_MULTIPLAYER);
1329 // the "lock" button has been pressed
1330 multi_ts_lock_pressed();
1332 // disable the button if it is now locked
1333 if(multi_ts_is_locked()){
1334 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1338 case MULTI_TS_COMMIT :
1339 multi_ts_commit_pressed();
1342 gamesnd_play_iface(SND_GENERAL_FAIL);
1347 // initialize all screen data, etc
1348 void multi_ts_init_graphics()
1352 // create the interface window
1353 Multi_ts_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
1354 Multi_ts_window.set_mask_bmap(Multi_ts_bitmap_mask_fname[gr_screen.res]);
1356 // load the background bitmap
1357 Multi_ts_bitmap = bm_load(Multi_ts_bitmap_fname[gr_screen.res]);
1358 if(Multi_ts_bitmap < 0){
1359 // we failed to load the bitmap - this is very bad
1363 // create the interface buttons
1364 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1365 // create the object
1366 if((idx == MULTI_TS_SHIPS_UP) || (idx == MULTI_TS_SHIPS_DOWN)){
1367 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);
1369 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);
1372 // set the sound to play when highlighted
1373 Multi_ts_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1375 // set the ani for the button
1376 Multi_ts_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ts_buttons[gr_screen.res][idx].filename);
1379 Multi_ts_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ts_buttons[gr_screen.res][idx].hotspot);
1384 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);
1385 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);
1386 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);
1387 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);
1388 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);
1391 // 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);
1392 // 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);
1396 // make the ship scrolling lists
1398 // if we're not the host of the game (or a tema captain in team vs. team mode), disable the lock button
1399 if (Netgame.type_flags & NG_TYPE_TEAM) {
1400 if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1401 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1404 if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1405 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1409 // initialize the snazzy menu stuff (for grabbing ships, names, etc)
1410 multi_ts_init_snazzy();
1412 // create the chatbox (again, should not be necessary at this point)
1415 // sync the interface as normal
1416 multi_ts_sync_interface();
1419 // blit all of the icons representing all wings
1420 void multi_ts_blit_wings()
1424 // blit them all blindly for now
1425 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1426 // if this ship doesn't exist, then continue
1427 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1431 // otherwise blit the ship icon or the "empty" icon
1432 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY){
1433 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);
1435 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));
1437 // if this is a team vs team game, and the slot is occupised by a team captain, put a c there
1438 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)){
1439 gr_set_color_fast(&Color_bright);
1440 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 ]]
1446 // blit all of the player callsigns under the correct ships
1447 void multi_ts_blit_wing_callsigns()
1450 char callsign[CALLSIGN_LEN+2];
1453 // blit them all blindly for now
1454 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1455 // if this ship doesn't exist, then continue
1456 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1460 // if there is a player in the slot
1461 if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
1462 // make sure the string fits
1463 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->player->callsign);
1465 // determine if this is a locked AI ship
1466 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
1467 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
1468 strcpy(callsign, NOX("<"));
1469 strcat(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1470 strcat(callsign, NOX(">"));
1472 strcpy(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1476 gr_force_fit_string(callsign, CALLSIGN_LEN, Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD]);
1478 // get the final length
1479 gr_get_string_size(&callsign_w, NULL, callsign);
1482 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)){
1483 gr_set_color_fast(&Color_text_active_hi);
1485 gr_set_color_fast(&Color_normal);
1487 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);
1491 // blit the ships on the avail list
1492 void multi_ts_blit_avail_ships()
1494 int display_count,ship_count,idx;
1497 // blit the availability of all ship counts
1500 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
1501 if(Ss_pool[idx] > 0){
1502 // if our starting display index is after this, then skip it
1503 if(ship_count < Multi_ts_avail_start){
1507 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));
1509 // blit the ship count available
1510 sprintf(count,"%d",Ss_pool[idx]);
1511 gr_set_color_fast(&Color_normal);
1512 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);
1514 // increment the counts
1520 // if we've reached the max amount we can display, then stop
1521 if(display_count >= MULTI_TS_AVAIL_MAX_DISPLAY){
1527 // initialize the snazzy menu stuff for dragging ships,players around
1528 void multi_ts_init_snazzy()
1530 // initialize the snazzy menu
1534 Multi_ts_snazzy_regions = 0;
1535 memset(Multi_ts_region,0,sizeof(MENU_REGION) * MULTI_TS_NUM_SNAZZY_REGIONS);
1537 // get a pointer to the mask bitmap data
1538 Multi_ts_mask_data = (ubyte*)Multi_ts_window.get_mask_data(&Multi_ts_mask_w, &Multi_ts_mask_h);
1540 // add the wing slots information
1541 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_0, 0);
1542 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_1, 0);
1543 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_2, 0);
1544 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_3, 0);
1545 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_0, 0);
1546 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_1, 0);
1547 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_2, 0);
1548 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_3, 0);
1549 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_0, 0);
1550 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_1, 0);
1551 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_2, 0);
1552 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_3, 0);
1554 // add the name slots information
1555 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_0, 0);
1556 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_1, 0);
1557 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_2, 0);
1558 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_3, 0);
1559 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_0, 0);
1560 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_1, 0);
1561 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_2, 0);
1562 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_3, 0);
1563 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_0, 0);
1564 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_1, 0);
1565 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_2, 0);
1566 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_3, 0);
1568 // add the available ships region
1569 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_0, 0);
1570 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_1, 0);
1571 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_2, 0);
1572 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_3, 0);
1575 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
1576 int multi_ts_region_type(int region)
1578 if((region == TSWING_0_SHIP_0) || (region == TSWING_0_SHIP_1) || (region == TSWING_0_SHIP_2) || (region == TSWING_0_SHIP_3) ||
1579 (region == TSWING_1_SHIP_0) || (region == TSWING_1_SHIP_1) || (region == TSWING_1_SHIP_2) || (region == TSWING_1_SHIP_3) ||
1580 (region == TSWING_2_SHIP_0) || (region == TSWING_2_SHIP_1) || (region == TSWING_2_SHIP_2) || (region == TSWING_2_SHIP_3) ){
1581 return MULTI_TS_SLOT_LIST;
1584 if((region == TSWING_0_NAME_0) || (region == TSWING_0_NAME_1) || (region == TSWING_0_NAME_2) || (region == TSWING_0_NAME_3) ||
1585 (region == TSWING_1_NAME_0) || (region == TSWING_1_NAME_1) || (region == TSWING_1_NAME_2) || (region == TSWING_1_NAME_3) ||
1586 (region == TSWING_2_NAME_0) || (region == TSWING_2_NAME_1) || (region == TSWING_2_NAME_2) || (region == TSWING_2_NAME_3) ){
1587 return MULTI_TS_PLAYER_LIST;
1590 if((region == TSWING_LIST_0) || (region == TSWING_LIST_1) || (region == TSWING_LIST_2) || (region == TSWING_LIST_3)){
1591 return MULTI_TS_AVAIL_LIST;
1597 // convert the region num to a ship slot index
1598 int multi_ts_slot_index(int region)
1601 case TSWING_0_SHIP_0:
1603 case TSWING_0_SHIP_1:
1605 case TSWING_0_SHIP_2:
1607 case TSWING_0_SHIP_3:
1609 case TSWING_1_SHIP_0:
1611 case TSWING_1_SHIP_1:
1613 case TSWING_1_SHIP_2:
1615 case TSWING_1_SHIP_3:
1617 case TSWING_2_SHIP_0:
1619 case TSWING_2_SHIP_1:
1621 case TSWING_2_SHIP_2:
1623 case TSWING_2_SHIP_3:
1630 // convert the region num to an avail list index (starting from absolute 0)
1631 int multi_ts_avail_index(int region)
1647 // convert the region num to a player slot index
1648 int multi_ts_player_index(int region)
1651 case TSWING_0_NAME_0:
1653 case TSWING_0_NAME_1:
1655 case TSWING_0_NAME_2:
1657 case TSWING_0_NAME_3:
1659 case TSWING_1_NAME_0:
1661 case TSWING_1_NAME_1:
1663 case TSWING_1_NAME_2:
1665 case TSWING_1_NAME_3:
1667 case TSWING_2_NAME_0:
1669 case TSWING_2_NAME_1:
1671 case TSWING_2_NAME_2:
1673 case TSWING_2_NAME_3:
1680 // blit any active ship information text
1681 void multi_ts_blit_ship_info()
1687 // if we don't have a valid ship selected, do nothing
1688 if(Multi_ts_select_ship_class == -1){
1692 // get the ship class
1693 sip = &Ship_info[Multi_ts_select_ship_class];
1696 y_start = Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_Y_COORD];
1700 // blit the ship class (name)
1701 gr_set_color_fast(&Color_normal);
1702 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Class",739));
1703 if(strlen(sip->name)){
1704 gr_set_color_fast(&Color_bright);
1705 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->name);
1709 // blit the ship type
1710 gr_set_color_fast(&Color_normal);
1711 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Type",740));
1712 if((sip->type_str != NULL) && strlen(sip->type_str)){
1713 gr_set_color_fast(&Color_bright);
1714 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->type_str);
1718 // blit the ship length
1719 gr_set_color_fast(&Color_normal);
1720 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Length",741));
1721 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1722 gr_set_color_fast(&Color_bright);
1723 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->ship_length);
1727 // blit the max velocity
1728 gr_set_color_fast(&Color_normal);
1729 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Max Velocity",742));
1730 sprintf(str,XSTR("%d m/s",743),(int)sip->max_vel.xyz.z);
1731 gr_set_color_fast(&Color_bright);
1732 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,str);
1735 // blit the maneuverability
1736 gr_set_color_fast(&Color_normal);
1737 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Maneuverability",744));
1738 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1739 gr_set_color_fast(&Color_bright);
1740 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->maneuverability_str);
1745 gr_set_color_fast(&Color_normal);
1746 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Armor",745));
1747 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1748 gr_set_color_fast(&Color_bright);
1749 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->armor_str);
1753 // blit the gun mounts
1754 gr_set_color_fast(&Color_normal);
1755 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Gun Mounts",746));
1756 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1757 gr_set_color_fast(&Color_bright);
1758 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->gun_mounts);
1762 // blit the missile banke
1763 gr_set_color_fast(&Color_normal);
1764 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Missile Banks",747));
1765 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1766 gr_set_color_fast(&Color_bright);
1767 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->missile_banks);
1771 // blit the manufacturer
1772 gr_set_color_fast(&Color_normal);
1773 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Manufacturer",748));
1774 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1775 gr_set_color_fast(&Color_bright);
1776 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->manufacturer_str);
1780 // blit the _short_ text description
1782 Assert(Multi_ts_ship_info_line_count < 3);
1783 gr_set_color_fast(&Color_normal);
1784 for(idx=0;idx<Multi_ts_ship_info_line_count;idx++){
1785 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, Multi_ts_ship_info_lines[idx]);
1792 // blit the status bar
1793 void multi_ts_blit_status_bar()
1799 // mode specific text
1800 switch(Multi_ts_status_bar_mode){
1802 strcpy(text,XSTR("Ships/Weapons Locked",749));
1806 strcpy(text,XSTR("Ships/Weapons Are Now Free",750));
1811 // if we should be blitting
1813 gr_get_string_size(&text_w,NULL,text);
1814 gr_set_color_fast(&Color_bright_blue);
1815 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);
1819 // assign the correct players to the correct slots
1820 void multi_ts_init_players()
1824 // if i'm an observer, i have no ship
1825 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1826 Net_player->p_info.ship_index = -1;
1829 // initialize all players and observer
1830 for(idx=0;idx<MAX_PLAYERS;idx++){
1831 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1832 if(MULTI_OBSERVER(Net_players[idx])){
1833 Net_players[idx].p_info.ship_index = -1;
1835 Multi_ts_team[Net_players[idx].p_info.team].multi_ts_player[Net_players[idx].p_info.ship_index] = &Net_players[idx];
1841 // assign the correct objnums to the correct slots
1842 void multi_ts_init_objnums()
1844 int idx,s_idx,team_index,slot_index;
1847 // zero out the indices
1848 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1849 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1850 Multi_ts_team[idx].multi_ts_objnum[s_idx] = -1;
1854 // set all the objnums
1855 objp = GET_FIRST(&obj_used_list);
1856 while(objp != END_OF_LIST(&obj_used_list)){
1857 // if its a ship, get its slot index (if any)
1858 if(objp->type == OBJ_SHIP){
1859 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1860 if((slot_index != -1) && (team_index != -1)){
1861 Multi_ts_team[team_index].multi_ts_objnum[slot_index] = Ships[objp->instance].objnum;
1865 objp = GET_NEXT(objp);
1869 // get the proper team and slot index for the given ship name
1870 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index)
1874 // set the return values to default values
1878 // if we're in team vs. team mode
1879 if(Netgame.type_flags & NG_TYPE_TEAM){
1880 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1881 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1882 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
1884 *slot_index = s_idx;
1890 // if we're _not_ in team vs. team mode
1892 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1893 if(!stricmp(ship_name,Multi_ts_slot_names[idx])){
1902 // function to return the shipname of the ship in the slot designated by the team and slot
1904 char *multi_ts_get_shipname( int team, int slot_index )
1906 if ( Netgame.type_flags & NG_TYPE_TEAM ) {
1907 Assert( (team >= 0) && (team < MULTI_TS_MAX_TEAMS) );
1908 return Multi_ts_slot_team_names[team][slot_index];
1910 Assert( team == 0 );
1911 return Multi_ts_slot_names[slot_index];
1915 // assign the correct flags to the correct slots
1916 void multi_ts_init_flags()
1920 // zero out the flags
1921 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1922 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1923 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_NONE;
1927 // in a team vs. team situation
1928 if(Netgame.type_flags & NG_TYPE_TEAM){
1929 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1930 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1931 // if the there is an objnum here but no ship class, we know its currently empty
1932 if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class == -1)){
1933 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_EMPTY;
1934 } else if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class != -1)){
1935 Multi_ts_team[idx].multi_ts_flag[s_idx] = Wss_slots_teams[idx][s_idx].ship_class;
1940 // in a non team vs. team situation
1942 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1943 // if the there is an objnum here but no ship class, we know its currently empty
1944 if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class == -1)){
1945 Multi_ts_team[0].multi_ts_flag[idx] = MULTI_TS_FLAG_EMPTY;
1946 } else if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class != -1)){
1947 Multi_ts_team[0].multi_ts_flag[idx] = Wss_slots[idx].ship_class;
1953 // handle an available ship scroll down button press
1954 void multi_ts_avail_scroll_down()
1956 if((Multi_ts_avail_count - Multi_ts_avail_start) > MULTI_TS_AVAIL_MAX_DISPLAY){
1957 gamesnd_play_iface(SND_USER_SELECT);
1958 Multi_ts_avail_start++;
1960 gamesnd_play_iface(SND_GENERAL_FAIL);
1964 // handle an available ship scroll up button press
1965 void multi_ts_avail_scroll_up()
1967 if(Multi_ts_avail_start > 0){
1968 gamesnd_play_iface(SND_USER_SELECT);
1969 Multi_ts_avail_start--;
1971 gamesnd_play_iface(SND_GENERAL_FAIL);
1975 // handle all mouse events (clicking, dragging, and dropping)
1976 void multi_ts_handle_mouse()
1978 int snazzy_region,snazzy_action;
1979 int region_type,region_index,region_empty;
1980 int mouse_x,mouse_y,ship_class;
1982 // get the mouse coords
1983 mouse_get_pos(&mouse_x,&mouse_y);
1985 // do frame for the snazzy menu
1986 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);
1992 if(snazzy_region != -1){
1993 region_type = multi_ts_region_type(snazzy_region);
1994 Assert(region_type != -1);
1996 // determine what type of region the mouse is over and the appropriate index
1997 switch(region_type){
1998 case MULTI_TS_AVAIL_LIST:
1999 region_index = multi_ts_avail_index(snazzy_region);
2000 ship_class = multi_ts_get_avail_ship_class(region_index);
2002 if(ship_class == -1){
2005 region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1;
2008 case MULTI_TS_SLOT_LIST:
2009 region_index = multi_ts_slot_index(snazzy_region);
2010 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] >= 0) ? 0 : 1;
2012 ship_class = Wss_slots[region_index].ship_class;
2015 case MULTI_TS_PLAYER_LIST:
2016 region_index = multi_ts_player_index(snazzy_region);
2017 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL) ? 0 : 1;
2022 // maybe play a "highlight" sound
2023 switch(region_type){
2024 case MULTI_TS_PLAYER_LIST:
2025 if((Multi_ts_hotspot_index != region_index) && (region_index >= 0) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL)){
2026 gamesnd_play_iface(SND_USER_SELECT);
2031 // set the current frame mouse hotspot vars
2032 Multi_ts_hotspot_type = region_type;
2033 Multi_ts_hotspot_index = region_index;
2035 // if we currently have clicked on something and have just released it
2036 if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2037 Multi_ts_clicked_flag = 0;
2040 // if we're currently not carrying anything and the user has clicked
2041 if(!Multi_ts_carried_flag && !Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && !region_empty){
2042 // set the "clicked" flag
2043 Multi_ts_clicked_flag = 1;
2045 // check to see if he clicked on a ship type and highlight if necessary
2046 switch(region_type){
2047 // selected a ship in the wing slots
2048 case MULTI_TS_SLOT_LIST:
2049 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
2050 Multi_ts_select_index = region_index;
2051 multi_ts_select_ship();
2054 // selected a ship on the avail list
2055 case MULTI_TS_AVAIL_LIST:
2056 Multi_ts_select_type = MULTI_TS_AVAIL_LIST;
2057 Multi_ts_select_index = region_index;
2058 multi_ts_select_ship();
2061 // selected something else - unselect
2063 Multi_ts_select_type = -1;
2064 Multi_ts_select_index = -1;
2065 Multi_ts_select_ship_class = -1;
2069 Multi_ts_clicked_x = mouse_x;
2070 Multi_ts_clicked_y = mouse_y;
2073 // if we had something clicked and have started dragging it
2074 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))){
2075 // if this player is an observer, he shouldn't be able to do jack
2076 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2080 // first we check for illegal conditions (any case where he cannot grab what he is attempting to grab)
2081 switch(region_type){
2082 case MULTI_TS_AVAIL_LIST :
2083 // if players are not yet locked, can't grab ships
2084 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2092 case MULTI_TS_SLOT_LIST:
2093 // if players are not yet locked, can't grab ships
2094 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2098 if(multi_ts_disabled_slot(region_index)){
2099 multi_ts_maybe_host_only_popup();
2102 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] < 0){
2106 case MULTI_TS_PLAYER_LIST:
2107 if(!multi_ts_can_grab_player(region_index)){
2114 Multi_ts_clicked_flag = 0;
2115 Multi_ts_carried_flag = 1;
2117 // set up the carried icon here
2118 Multi_ts_carried_from_type = region_type;
2119 Multi_ts_carried_from_index = region_index;
2120 Multi_ts_carried_ship_class = ship_class;
2123 // if we were carrying something but have dropped it
2124 if(Multi_ts_carried_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2125 Multi_ts_carried_flag = 0;
2126 Multi_ts_clicked_flag = 0;
2128 // if we're not allowed to drop onto this slot
2129 if((region_type == MULTI_TS_SLOT_LIST) && multi_ts_disabled_slot(region_index)){
2130 multi_ts_maybe_host_only_popup();
2133 // if we're over some kind of valid region, apply
2134 multi_ts_drop(Multi_ts_carried_from_type,Multi_ts_carried_from_index,region_type,region_index,Multi_ts_carried_ship_class);
2138 // can the specified player perform the action he is attempting
2139 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2145 // get the appropriate player
2146 if(player_index == -1){
2149 pl = &Net_players[player_index];
2152 // get the operation type
2153 op_type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2155 // if either of the indices are bogus, then bail
2156 if((from_index == -1) || (to_index == -1)){
2161 case TS_GRAB_FROM_LIST:
2162 // if there are no more of this ship class, its no go
2163 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2167 // if he's not allowed to touch the wing slot
2168 if(multi_ts_disabled_slot(to_index,player_index)){
2172 // if the slot he's trying to drop it on is "permanently" empty
2173 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2178 case TS_SWAP_LIST_SLOT:
2179 // if there are no more of this ship class, its no go
2180 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2184 // if he's not allowed to touch the wing slot
2185 if(multi_ts_disabled_slot(to_index,player_index)){
2189 // if the slot we're trying to move to is invalid, then do nothing
2190 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2194 // if the slot he's trying to drop it on is "permanently" empty
2195 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2200 case TS_SWAP_SLOT_SLOT:
2201 // if he's not allowed to touch one of the slots, its no go
2202 if(multi_ts_disabled_slot(from_index,player_index) || multi_ts_disabled_slot(to_index,player_index)){
2206 // if the slot we're taking from is invalid
2207 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2211 // if the slot he's trying to drop it on is "permanently" empty
2212 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2217 case TS_DUMP_TO_LIST:
2218 // if he's not allowed to be touching the slot to begin with, it no go
2219 if(multi_ts_disabled_slot(from_index,player_index)){
2223 // if the slot we're trying to move to is invalid, then do nothing
2224 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2229 case TS_SWAP_PLAYER_PLAYER:
2230 // if his team is already locked, he cannot do this
2231 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2235 // if there isn't a player at one of the positions
2236 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)){
2240 // if this is not a player ship type object
2241 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2242 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2243 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2248 if(Netgame.type_flags & NG_TYPE_TEAM){
2249 // if he's not the team captain, he cannot do this
2250 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2254 // if he's not the host, he cannot do this
2255 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2261 case TS_MOVE_PLAYER:
2262 // if his team is already locked, he cannot do this
2263 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2267 // if there isn't a player at the _from_
2268 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL){
2272 // if there is no ship at the _to_ location
2273 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] < 0){
2277 // if this is not a player ship type object
2278 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2279 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2280 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2285 if(Netgame.type_flags & NG_TYPE_TEAM){
2286 // if he's not the team captain, he cannot do this
2287 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2291 // if he's not the host, he cannot do this
2292 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2306 // determine the kind of drag and drop operation this is
2307 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)
2311 // get the appropriate player
2312 if(player_index == -1){
2315 pl = &Net_players[player_index];
2319 // came from the ship avail list
2320 case MULTI_TS_AVAIL_LIST :
2322 if(to_type == MULTI_TS_AVAIL_LIST){
2326 // if placing it on a slot
2327 if(to_type == MULTI_TS_SLOT_LIST){
2328 if(Wss_slots_teams[pl->p_info.team][to_index].ship_class == -1){
2329 return TS_GRAB_FROM_LIST;
2331 return TS_SWAP_LIST_SLOT;
2336 // came from the ship slots
2337 case MULTI_TS_SLOT_LIST :
2338 if(to_type == MULTI_TS_SLOT_LIST){
2339 return TS_SWAP_SLOT_SLOT;
2341 if(to_type == MULTI_TS_AVAIL_LIST){
2342 return TS_DUMP_TO_LIST;
2346 // came from the player lists
2347 case MULTI_TS_PLAYER_LIST :
2348 if(to_type == MULTI_TS_PLAYER_LIST){
2349 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL){
2350 return TS_MOVE_PLAYER;
2352 return TS_SWAP_PLAYER_PLAYER;
2361 void multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2363 int size,update,sound;
2364 ubyte wss_data[MAX_PACKET_SIZE-20];
2367 // determine what kind of operation this is
2368 int type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2370 // get the proper net player
2371 if(player_index == -1){
2374 pl = &Net_players[player_index];
2377 // set the proper pool pointers
2378 ss_set_team_pointers(pl->p_info.team);
2382 case TS_SWAP_SLOT_SLOT :
2383 nprintf(("Network","Apply swap slot slot %d %d\n",from_index,to_index));
2384 update = ss_swap_slot_slot(from_index,to_index,&sound);
2386 case TS_DUMP_TO_LIST :
2387 nprintf(("Network","Apply dump to list %d %d\n",from_index,to_index));
2388 update = ss_dump_to_list(from_index,ship_class,&sound);
2390 case TS_SWAP_LIST_SLOT :
2391 nprintf(("Network","Apply swap list slot %d %d\n",from_index,to_index));
2392 update = ss_swap_list_slot(ship_class,to_index,&sound);
2394 case TS_GRAB_FROM_LIST :
2395 nprintf(("Network","Apply grab from list %d %d\n",from_index,to_index));
2396 update = ss_grab_from_list(ship_class,to_index,&sound);
2398 case TS_SWAP_PLAYER_PLAYER :
2399 nprintf(("Network","Apply swap player player %d %d\n",from_index,to_index));
2400 update = multi_ts_swap_player_player(from_index,to_index,&sound,player_index);
2402 case TS_MOVE_PLAYER :
2403 nprintf(("Network","Apply move player %d %d\n",from_index,to_index));
2404 update = multi_ts_move_player(from_index,to_index,&sound,player_index);
2411 // if we're the host, send an update to all players
2412 if ( MULTIPLAYER_HOST ) {
2413 // send the correct type of update
2414 if(type == TS_SWAP_PLAYER_PLAYER){
2416 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound, player_index);
2417 send_wss_update_packet(pl->p_info.team,wss_data, size);
2419 // send a player slot update packet as well, so ship class information, etc is kept correct
2420 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,-1);
2423 // if the player index == -1, it means the action was done locally - so play a sound
2424 if((player_index == -1) && (sound != -1)){
2425 gamesnd_play_iface(sound);
2429 // sync the interface screen up ourselves, if necessary
2430 if(Net_player->p_info.team == pl->p_info.team){
2431 multi_ts_sync_interface();
2434 // make sure all flags are set properly for all teams
2435 multi_ts_init_flags();
2438 // set the proper pool pointers
2439 ss_set_team_pointers(Net_player->p_info.team);
2442 // drop a carried icon
2443 void multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2445 // if I'm the host, apply immediately
2446 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2447 // if this is a legal operation
2448 if(multi_ts_can_perform(from_type,from_index,to_type,to_index,ship_class,player_index)){
2449 multi_ts_apply(from_type,from_index,to_type,to_index,ship_class,player_index);
2451 nprintf(("Network","Could not apply operation!\n"));
2454 // otherwise send a request to the host
2456 send_wss_request_packet(Net_player->player_id, from_type, from_index, to_type, to_index, -1, ship_class, WSS_SHIP_SELECT);
2460 // swap two player positions
2461 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index)
2463 net_player *pl,*temp;
2465 // get the proper player pointer
2466 if(player_index == -1){
2469 pl = &Net_players[player_index];
2473 temp = Multi_ts_team[pl->p_info.team].multi_ts_player[to_index];
2474 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2475 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = temp;
2477 // update netplayer information if necessary
2478 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2479 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2480 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;
2482 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);
2484 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2485 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2486 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;
2488 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);
2491 // update ship flags
2492 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2493 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2494 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2495 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2497 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2498 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2499 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2500 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2503 // recalcalate which slots are locked/unlocked, etc
2504 ss_recalc_multiplayer_slots();
2506 // send an update packet to all players
2507 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2508 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2509 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2512 *sound = SND_ICON_DROP;
2518 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index)
2522 // get the proper player pointer
2523 if(player_index == -1){
2526 pl = &Net_players[player_index];
2530 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2531 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = NULL;
2533 // update netplayer information if necessary
2534 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2535 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2536 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;
2538 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);
2540 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2541 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2542 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;
2544 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);
2547 // update ship flags
2548 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2549 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2550 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2551 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2553 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2554 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2555 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2556 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2559 // recalcalate which slots are locked/unlocked, etc
2560 ss_recalc_multiplayer_slots();
2562 // send an update packet to all players
2563 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2564 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2565 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2568 *sound = SND_ICON_DROP;
2573 // get the ship class of the current index in the avail list or -1 if none exists
2574 int multi_ts_get_avail_ship_class(int index)
2576 int ship_count,class_index;
2578 ship_count = index + Multi_ts_avail_start;
2580 while((ship_count >= 0) && (class_index < MAX_SHIP_TYPES)){
2581 if(Ss_pool[class_index] > 0){
2585 if(ship_count >= 0){
2597 // blit the currently carried icon (if any)
2598 void multi_ts_blit_carried_icon()
2601 int offset_x,offset_y,callsign_w;
2602 char callsign[CALLSIGN_LEN+2];
2604 // if we're not carrying anything, then return
2605 if(!Multi_ts_carried_flag){
2609 // get the mouse position
2610 mouse_get_pos(&x,&y);
2612 // if we're carrying an icon of some kind
2613 switch(Multi_ts_carried_from_type){
2614 case MULTI_TS_SLOT_LIST:
2615 offset_x = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2616 offset_y = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2619 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2621 case MULTI_TS_AVAIL_LIST:
2622 offset_x = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2623 offset_y = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2626 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2628 case MULTI_TS_PLAYER_LIST:
2629 // get the final length of the string so we can calculate a valid offset
2630 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->player->callsign);
2631 gr_force_fit_string(callsign,CALLSIGN_LEN,Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD]);
2632 gr_get_string_size(&callsign_w,NULL,callsign);
2634 // calculate the offsets
2635 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);
2636 offset_y = Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2638 gr_set_color_fast(&Color_normal);
2639 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);
2646 // if the (console) player is allowed to grab a player slot at this point
2647 int multi_ts_can_grab_player(int slot_index, int player_index)
2651 // get a pointe rto the proper net player
2652 if(player_index == -1){
2655 pl = &Net_players[player_index];
2658 // if the players are locked in any case, he annot grab it
2659 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2663 if(Netgame.type_flags & NG_TYPE_TEAM){
2664 // if he's not the team captain, he cannot do this
2665 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2669 // if he's not the host, he cannot do this
2670 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2675 // if the slot is empty
2676 if(Multi_ts_team[pl->p_info.team].multi_ts_player[slot_index] == NULL){
2683 // get the team # of the given ship
2684 int multi_ts_get_team(char *ship_name)
2688 // lookup through all team ship names
2689 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
2690 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
2691 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
2697 // always on team 0 if not found otherwise
2701 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2702 int multi_ts_avail_bmap_num(int slot_index)
2704 // if this slot has been highlighted for informational purposes
2705 if((Multi_ts_select_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_select_index == slot_index)){
2706 return ICON_FRAME_SELECTED;
2709 // if its otherwise being lit by the mouse
2710 if((Multi_ts_hotspot_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_hotspot_index == slot_index)){
2711 return ICON_FRAME_HOT;
2714 return ICON_FRAME_NORMAL;
2717 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2718 int multi_ts_slot_bmap_num(int slot_index)
2720 // special case - slot is disabled, its my ship and the host hasn't locked the ships yet
2721 if(multi_ts_disabled_high_slot(slot_index)){
2722 return ICON_FRAME_DISABLED_HIGH;
2725 // if this slot is disabled for us, then show it as such
2726 if(multi_ts_disabled_slot(slot_index)){
2727 return ICON_FRAME_DISABLED;
2730 // if this slot has been highlighted for informational purposes
2731 if((Multi_ts_select_type == MULTI_TS_SLOT_LIST) && (Multi_ts_select_index == slot_index)){
2732 return ICON_FRAME_SELECTED;
2735 // if this is our ship, then highlight it as so
2736 if(Net_player->p_info.ship_index == slot_index){
2737 return ICON_FRAME_PLAYER;
2740 // if its otherwise being lit by the mouse
2741 if((Multi_ts_hotspot_type == MULTI_TS_SLOT_LIST) && (Multi_ts_hotspot_index == slot_index)){
2742 return ICON_FRAME_HOT;
2745 // normal unhighlighted frame
2746 return ICON_FRAME_NORMAL;
2749 // select the given slot and setup any information, etc
2750 void multi_ts_select_ship()
2754 int n_chars[MAX_BRIEF_LINES];
2755 char ship_desc[1000];
2756 char *p_str[MAX_BRIEF_LINES];
2760 // blast all current text
2761 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2762 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2764 // get the selected ship class
2765 Assert(Multi_ts_select_index >= 0);
2766 Multi_ts_select_ship_class = -1;
2767 switch(Multi_ts_select_type){
2768 case MULTI_TS_SLOT_LIST:
2769 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
2771 case MULTI_TS_AVAIL_LIST:
2772 Multi_ts_select_ship_class = multi_ts_get_avail_ship_class(Multi_ts_select_index);
2773 // if he has selected an empty slot, don't do anything
2774 if(Multi_ts_select_ship_class < 0){
2779 // should always have one of the 2 above types selected
2784 // split the text info up
2786 Assert(Multi_ts_select_ship_class >= 0);
2787 Assert((Ship_info[Multi_ts_select_ship_class].desc != NULL) && strlen(Ship_info[Multi_ts_select_ship_class].desc));
2789 // strip out newlines
2790 memset(ship_desc,0,1000);
2791 strcpy(ship_desc,Ship_info[Multi_ts_select_ship_class].desc);
2792 token = strtok(ship_desc,"\n");
2794 strcpy(Multi_ts_ship_info_text,token);
2795 while(token != NULL){
2796 token = strtok(NULL,"\n");
2798 strcat(Multi_ts_ship_info_text," ");
2799 strcat(Multi_ts_ship_info_text,token);
2804 if(strlen(Multi_ts_ship_info_text) > 0){
2805 // split the string into multiple lines
2806 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);
2808 // copy the split up lines into the text lines array
2809 for (idx=0;idx<n_lines;idx++ ) {
2810 Assert(n_chars[idx] < MULTI_TS_SHIP_INFO_MAX_LINE_LEN);
2811 strncpy(Multi_ts_ship_info_lines[idx], p_str[idx], n_chars[idx]);
2812 Multi_ts_ship_info_lines[idx][n_chars[idx]] = 0;
2813 drop_leading_white_space(Multi_ts_ship_info_lines[idx]);
2816 // get the line count
2817 Multi_ts_ship_info_line_count = n_lines;
2819 // set the line count to
2820 Multi_ts_ship_info_line_count = 0;
2825 // handle all details when the commit button is pressed (including possibly reporting errors/popups)
2826 void multi_ts_commit_pressed()
2828 // if my team's slots are still not "locked", we cannot commit unless we're the only player in the game
2829 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2830 if(multi_num_players() != 1){
2831 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("Players have not yet been assigned to their ships",751));
2834 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
2838 // check to see if its not ok for this player to commit
2839 switch(multi_ts_ok_to_commit()){
2840 // yes, it _is_ ok to commit
2842 extern void commit_pressed();
2846 // player has not assigned all necessary ships
2848 gamesnd_play_iface(SND_GENERAL_FAIL);
2849 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("You have not yet assigned all necessary ships",752));
2852 // there are ships without primary weapons
2854 gamesnd_play_iface(SND_GENERAL_FAIL);
2855 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without primary weapons!",753));
2858 // there are ships without secondary weapons
2860 gamesnd_play_iface(SND_GENERAL_FAIL);
2861 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without secondary weapons!",754));
2866 // is it ok for this player to commit
2867 int multi_ts_ok_to_commit()
2870 int primary_ok,secondary_ok;
2872 // if this player is an observer, he can always commit
2873 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2877 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2878 // if this is a player slot this player can modify and it is empty, then he cannot continue
2879 // implies there is never an object in this slot
2880 if((Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2881 // implies player can't touch this slot anyway
2882 !multi_ts_disabled_slot(idx) &&
2883 // implies that there should be a player ship here but there isn't
2884 ((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)) ){
2888 // 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
2889 if( (Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2890 ((Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER) ||
2891 (Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP)) &&
2892 !multi_ts_disabled_slot(idx)){
2896 // go through all weapons in the list
2897 for(s_idx=0;s_idx<MAX_WL_WEAPONS;s_idx++){
2898 // if this slot has a weapon with a greater than 0 count, check
2899 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)){
2900 switch(Weapon_info[Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx]].subtype){
2914 // if we've got both primary and secondary weapons
2915 if(primary_ok && secondary_ok){
2920 // if the ship doesn't have primary weapons
2925 // if the ship doesn't have secondary weapons
2935 // check to see that no illegal ship settings have occurred
2936 void multi_ts_check_errors()
2942 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2943 if(Multi_ts_team[0].multi_ts_objnum[idx] == -1){
2947 shipp = &Ships[Objects[Multi_ts_team[0].multi_ts_objnum[idx]].instance];
2948 Assert((shipp->weapons.current_primary_bank != -1) && (shipp->weapons.current_secondary_bank != -1));
2954 // ------------------------------------------------------------------------------------------------------
2955 // TEAM SELECT PACKET HANDLERS
2958 // send a player slot position update
2959 void send_pslot_update_packet(int team,int code,int sound)
2961 ubyte data[MAX_PACKET_SIZE],stop,val;
2964 int packet_size = 0;
2967 // build the header and add the data
2968 BUILD_HEADER(SLOT_UPDATE);
2978 // add the sound to play
2979 s_sound = (short)sound;
2980 ADD_DATA_S16(s_sound);
2982 // add data based upon the packet code
2984 case TS_CODE_LOCK_TEAM:
2985 // don't have to do anything
2987 case TS_CODE_PLAYER_UPDATE:
2988 // only the host should ever be doing this
2989 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
2991 // add individual slot data
2992 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
2993 if(Multi_ts_team[team].multi_ts_flag[idx] != MULTI_TS_FLAG_NONE){
3002 // add the ship class
3003 val = (ubyte)Wss_slots_teams[team][idx].ship_class;
3006 // add the objnum we're working with
3007 i_tmp = Multi_ts_team[team].multi_ts_objnum[idx];
3008 ADD_DATA_S32(i_tmp);
3010 // add a byte indicating if a player is here or not
3011 if(Multi_ts_team[team].multi_ts_player[idx] == NULL){
3018 // if there's a player, add his address
3020 ADD_DATA_S16(Multi_ts_team[team].multi_ts_player[idx]->player_id);
3022 // should also update his p_info settings locally
3023 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_class = Wss_slots_teams[team][idx].ship_class;
3024 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_index = idx;
3027 // 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)
3028 if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER){
3030 } else if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP){
3038 // add a final stop byte
3047 // send the packet to the standalone
3048 if(Net_player->flags & NETINFO_FLAG_AM_MASTER) {
3049 multi_io_send_to_all_reliable(data, packet_size);
3051 multi_io_send_reliable(Net_player, data, packet_size);
3055 // process a player slot position update
3056 void process_pslot_update_packet(ubyte *data, header *hinfo)
3058 int offset = HEADER_LENGTH;
3060 int player_index,idx,team,code,objnum;
3063 ubyte stop,val,slot_num,ship_class;
3065 my_index = Net_player->p_info.ship_index;
3067 // if we're the standalone, then we should be routing this data to all the other clients
3069 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3070 // fill in the address information of where this came from
3071 player_index = find_player_id(hinfo->id);
3072 Assert(player_index != -1);
3083 // get the sound to play
3084 GET_DATA_S16(sound);
3086 // process the different opcodes
3088 case TS_CODE_LOCK_TEAM:
3090 Multi_ts_team[team].multi_players_locked = 1;
3092 // if this was my team, sync stuff up
3093 if((team == Net_player->p_info.team) && !(Game_mode & GM_STANDALONE_SERVER)){
3094 multi_ts_set_status_bar_mode(1);
3095 multi_ts_sync_interface();
3096 ss_recalc_multiplayer_slots();
3099 // if this is the standalone server, we need to re-route the packet here and there
3100 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3101 // in team vs team mode, only a team captain should ever be sending this
3102 if(Netgame.type_flags & NG_TYPE_TEAM){
3103 Assert(Net_players[player_index].flags & NETINFO_FLAG_TEAM_CAPTAIN);
3105 // in any other mode, it better be coming from the game host
3107 Assert(Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST);
3110 // re-route to all other players
3111 for(idx=0;idx<MAX_PLAYERS;idx++){
3112 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
3113 multi_io_send_reliable(&Net_players[idx], data, offset);
3118 case TS_CODE_PLAYER_UPDATE:
3119 // get the first stop byte
3121 while(stop != 0xff){
3125 // get the ship class
3126 GET_DATA(ship_class);
3129 GET_DATA_S32(objnum);
3131 // flag indicating if a player is in this slot
3134 // look the player up
3135 GET_DATA_S16(player_id);
3136 player_index = find_player_id(player_id);
3138 // if we couldn't find him
3139 if(player_index == -1){
3140 nprintf(("Network","Couldn't find player for pslot update!\n"));
3141 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3143 // if we found him, assign him to this ship
3145 Net_players[player_index].p_info.ship_class = (int)ship_class;
3146 Net_players[player_index].p_info.ship_index = (int)slot_num;
3147 multi_assign_player_ship(player_index,&Objects[objnum],(int)ship_class);
3150 Multi_ts_team[team].multi_ts_player[slot_num] = &Net_players[player_index];
3152 // if this was me and my ship index changed, update the weapon select screen
3153 if(my_index != Net_player->p_info.ship_index){
3154 wl_reset_selected_slot();
3156 my_index = Net_player->p_info.ship_index;
3160 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3163 // get the ship flag byte
3165 Objects[objnum].flags &= ~(OF_PLAYER_SHIP | OF_COULD_BE_PLAYER);
3168 Objects[objnum].flags |= OF_PLAYER_SHIP;
3171 obj_set_flags( &Objects[objnum], Objects[objnum].flags | OF_COULD_BE_PLAYER );
3175 // get the next stop byte
3178 // if we have a sound we're supposed to play
3179 if((sound != -1) && !(Game_mode & GM_STANDALONE_SERVER) && (gameseq_get_state() == GS_STATE_TEAM_SELECT)){
3180 gamesnd_play_iface(sound);
3183 // if i'm the standalone server, I should rebroadcast this packet
3184 if(Game_mode & GM_STANDALONE_SERVER){
3185 for(idx=0;idx<MAX_PLAYERS;idx++){
3186 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_HOST(Net_players[idx]) && (Net_player != &Net_players[idx])){
3187 multi_io_send_reliable(&Net_players[idx], data, offset);
3195 // recalculate stuff
3196 if(!(Game_mode & GM_STANDALONE_SERVER)){
3197 ss_recalc_multiplayer_slots();