2 * $Logfile: /Freespace2/code/Network/MultiTeamSelect.cpp $
7 * Multiplayer Team Selection Code
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 27 9/13/99 12:54p Jefff
17 * 26 9/12/99 3:21p Jefff
18 * commit button coord fix in 640
20 * 25 8/05/99 9:57p Jefff
21 * fixed some button wierdness
23 * 24 8/05/99 5:08p Jefff
24 * fixed some location probs
26 * 23 7/28/99 5:34p Dave
27 * Nailed the missing stats bug to the wall. Problem was optimized build
28 * and using GET_DATA() with array elements. BLECH.
30 * 22 7/24/99 6:02p Jefff
31 * Added "lock" text to lock button
33 * 21 5/03/99 8:32p Dave
34 * New version of multi host options screen.
36 * 20 3/25/99 6:36p Neilk
37 * more hires coord fixes
39 * 19 3/25/99 2:44p Neilk
42 * 18 3/23/99 11:56a Neilk
43 * new source safe checkin
45 * 17 3/10/99 6:50p Dave
46 * Changed the way we buffer packets for all clients. Optimized turret
47 * fired packets. Did some weapon firing optimizations.
49 * 16 3/09/99 6:24p Dave
50 * More work on object update revamping. Identified several sources of
51 * unnecessary bandwidth.
53 * 15 2/21/99 6:02p Dave
54 * Fixed standalone WSS packets.
56 * 14 2/11/99 3:08p Dave
57 * PXO refresh button. Very preliminary squad war support.
59 * 13 2/01/99 5:55p Dave
60 * Removed the idea of explicit bitmaps for buttons. Fixed text
61 * highlighting for disabled gadgets.
63 * 12 1/30/99 5:08p Dave
64 * More new hi-res stuff.Support for nice D3D textures.
66 * 11 1/30/99 1:29a Dave
67 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
68 * screen. Fixed beam weapon death messages.
70 * 10 1/29/99 5:07p Dave
71 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
74 * 9 1/13/99 7:19p Neilk
75 * Converted Mission Brief, Barracks, Synch to high res support
77 * 8 12/18/98 1:13a Dave
78 * Rough 1024x768 support for Direct3D. Proper detection and usage through
81 * 7 11/30/98 1:07p Dave
82 * 16 bit conversion, first run.
84 * 6 11/19/98 8:04a Dave
85 * Full support for D3-style reliable sockets. Revamped packet lag/loss
86 * system, made it receiver side and at the lowest possible level.
88 * 5 11/17/98 11:12a Dave
89 * Removed player identification by address. Now assign explicit id #'s.
91 * 4 11/05/98 5:55p Dave
92 * Big pass at reducing #includes
94 * 3 10/13/98 9:29a Dave
95 * Started neatening up freespace.h. Many variables renamed and
96 * reorganized. Added AlphaColors.[h,cpp]
98 * 2 10/07/98 10:53a Dave
101 * 1 10/07/98 10:50a Dave
103 * 112 9/18/98 2:22a Dave
104 * Fixed freespace-side PXO api to correctly handle length 10 id strings.
105 * Fixed team select screen to handle alpha/beta/gamma ships which are not
106 * marked as OF_PLAYER_SHIP
108 * 111 9/17/98 3:08p Dave
109 * PXO to non-pxo game warning popup. Player icon stuff in create and join
110 * game screens. Upped server count refresh time in PXO to 35 secs (from
113 * 110 8/20/98 5:31p Dave
114 * Put in handy multiplayer logfile system. Now need to put in useful
115 * applications of it all over the code.
117 * 109 8/07/98 10:17a Allender
118 * use obj_set_flags for setting COULD_BE_PLAYER flag to trap bugs
120 * 108 7/24/98 9:27a Dave
121 * Tidied up endgame sequencing by removing several old flags and
122 * standardizing _all_ endgame stuff with a single function call.
124 * 107 6/13/98 6:01p Hoffoss
125 * Externalized all new (or forgot to be added) strings to all the code.
127 * 106 6/13/98 3:19p Hoffoss
128 * NOX()ed out a bunch of strings that shouldn't be translated.
130 * 105 5/19/98 8:35p Dave
131 * Revamp PXO channel listing system. Send campaign goals/events to
132 * clients for evaluation. Made lock button pressable on all screens.
134 * 104 5/19/98 11:23a Dave
135 * Change mask value for "lock" button.
137 * 103 5/18/98 12:41a Allender
138 * fixed subsystem problems on clients (i.e. not reporting properly on
139 * damage indicator). Fixed ingame join problem with respawns. minor
142 * 102 5/17/98 1:43a Dave
143 * Eradicated chatbox problems. Remove speed match for observers. Put in
144 * help screens for PXO. Fix messaging and end mission privelges. Fixed
145 * team select screen bugs. Misc UI fixes.
147 * 101 5/15/98 5:16p Dave
148 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
149 * status for team vs. team. Put in asserts to check for invalid team vs.
152 * 100 5/10/98 7:06p Dave
153 * Fix endgame sequencing ESC key. Changed how host options warning popups
154 * are done. Fixed pause/message scrollback/options screen problems in mp.
155 * Make sure observer HUD doesn't try to lock weapons.
159 #include "multiteamselect.h"
165 #include "linklist.h"
166 #include "gamesequence.h"
168 #include "multiutil.h"
169 #include "freespace.h"
170 #include "missionscreencommon.h"
171 #include "missionshipchoice.h"
172 #include "missionweaponchoice.h"
173 #include "missionbrief.h"
174 #include "missionparse.h"
175 #include "multimsgs.h"
176 #include "snazzyui.h"
180 #include "multi_endgame.h"
181 #include "alphacolors.h"
184 // ------------------------------------------------------------------------------------------------------
185 // TEAM SELECT DEFINES/VARS
188 // mission screen common data
189 extern int Next_screen;
194 #define MULTI_TS_PALETTE "InterfacePalette"
196 char *Multi_ts_bitmap_fname[GR_NUM_RESOLUTIONS] = {
197 "TeamSelect", // GR_640
198 "2_TeamSelect" // GR_1024
201 char *Multi_ts_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
202 "TeamSelect-M", // GR_640
203 "2_TeamSelect-M" // GR_1024
206 // constants for coordinate lookup
207 #define MULTI_TS_X_COORD 0
208 #define MULTI_TS_Y_COORD 1
209 #define MULTI_TS_W_COORD 2
210 #define MULTI_TS_H_COORD 3
212 #define MULTI_TS_NUM_BUTTONS 7
213 #define MULTI_TS_BRIEFING 0 // go to the briefing
214 #define MULTI_TS_SHIP_SELECT 1 // this screen
215 #define MULTI_TS_WEAPON_SELECT 2 // go to the weapon select screen
216 #define MULTI_TS_SHIPS_UP 3 // scroll the ships list up
217 #define MULTI_TS_SHIPS_DOWN 4 // scroll the ships list down
218 #define MULTI_TS_COMMIT 5 // commit
219 #define MULTI_TS_LOCK 6 // lock (free) ship/weapon select
221 ui_button_info Multi_ts_buttons[GR_NUM_RESOLUTIONS][MULTI_TS_NUM_BUTTONS] = {
223 ui_button_info("CB_00", 7, 3, 37, 7, 0),
224 ui_button_info("CB_01", 7, 19, 37, 23, 1),
225 ui_button_info("CB_02", 7, 35, 37, 39, 2),
226 ui_button_info("TSB_03", 5, 303, -1, -1, 3),
227 ui_button_info("TSB_04", 5, 454, -1, -1, 4),
228 ui_button_info("TSB_09", 571, 425, 572, 413, 9),
229 ui_button_info("TSB_34", 603, 374, 602, 364, 34)
233 ui_button_info("2_CB_00", 12, 5, 59, 12, 0),
234 ui_button_info("2_CB_01", 12, 31, 59, 37, 1),
235 ui_button_info("2_CB_02", 12, 56, 59, 62, 2),
236 ui_button_info("2_TSB_03", 8, 485, -1, -1, 3),
237 ui_button_info("2_TSB_04", 8, 727, -1, -1, 4),
238 ui_button_info("2_TSB_09", 914, 681, 937, 660, 9),
239 ui_button_info("2_TSB_34", 966, 599, 964, 584, 34)
244 // players locked ani graphic
245 #define MULTI_TS_NUM_LOCKED_BITMAPS 3
247 char *Multi_ts_bmap_names[GR_NUM_RESOLUTIONS][3] = {
259 int Multi_ts_locked_bitmaps[MULTI_TS_NUM_LOCKED_BITMAPS];
262 // snazzy menu regions
263 #define TSWING_0_SHIP_0 10
264 #define TSWING_0_SHIP_1 12
265 #define TSWING_0_SHIP_2 14
266 #define TSWING_0_SHIP_3 16
267 #define TSWING_1_SHIP_0 18
268 #define TSWING_1_SHIP_1 20
269 #define TSWING_1_SHIP_2 22
270 #define TSWING_1_SHIP_3 24
271 #define TSWING_2_SHIP_0 26
272 #define TSWING_2_SHIP_1 28
273 #define TSWING_2_SHIP_2 30
274 #define TSWING_2_SHIP_3 32
276 #define TSWING_0_NAME_0 11
277 #define TSWING_0_NAME_1 13
278 #define TSWING_0_NAME_2 15
279 #define TSWING_0_NAME_3 17
280 #define TSWING_1_NAME_0 19
281 #define TSWING_1_NAME_1 21
282 #define TSWING_1_NAME_2 23
283 #define TSWING_1_NAME_3 25
284 #define TSWING_2_NAME_0 27
285 #define TSWING_2_NAME_1 29
286 #define TSWING_2_NAME_2 31
287 #define TSWING_2_NAME_3 33
289 #define TSWING_LIST_0 5
290 #define TSWING_LIST_1 6
291 #define TSWING_LIST_2 7
292 #define TSWING_LIST_3 8
294 #define MULTI_TS_SLOT_LIST 0
295 #define MULTI_TS_PLAYER_LIST 1
296 #define MULTI_TS_AVAIL_LIST 2
299 #define MULTI_TS_NUM_SNAZZY_REGIONS 28
302 int Multi_ts_inited = 0;
303 int Multi_ts_snazzy_regions;
304 ubyte *Multi_ts_mask_data;
305 int Multi_ts_mask_w, Multi_ts_mask_h;
306 MENU_REGION Multi_ts_region[MULTI_TS_NUM_SNAZZY_REGIONS];
307 UI_WINDOW Multi_ts_window;
310 #define MULTI_TS_NUM_SHIP_SLOTS_TEAM 4 // # of ship slots in team v team
311 #define MULTI_TS_FLAG_NONE -2 // never has any ships
312 #define MULTI_TS_FLAG_EMPTY -1 // currently empty
313 char *Multi_ts_slot_names[MULTI_TS_NUM_SHIP_SLOTS] = { //
314 "alpha 1", "alpha 2", "alpha 3", "alpha 4",
315 "beta 1", "beta 2", "beta 3", "beta 4",
316 "gamma 1", "gamma 2", "gamma 3", "gamma 4"
318 char *Multi_ts_slot_team_names[MULTI_TS_MAX_TEAMS][MULTI_TS_NUM_SHIP_SLOTS_TEAM] = {
319 {"alpha 1", "alpha 2", "alpha 3", "alpha 4"},
320 {"zeta 1", "zeta 2", "zeta 3", "zeta 4"}
323 static int Multi_ts_slot_icon_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][2] = { // x,y
374 static int Multi_ts_slot_text_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][3] = { // x,y,width
376 {112,330,181-112}, // GR_640
377 {187,517,181-112} // GR_1024
380 {74,377,143-74}, // GR_640
381 {126,592,143-74} // GR_1024
384 {149,377,218-149},// GR_640
385 {248,592,218-149} // GR_1024
388 {112,424,181-112},// GR_640
389 {187,667,181-112} // GR_1024
392 {274,330,343-274},// GR_640
393 {446,517,343-274} // GR_1024
396 {236,377,305-236},// GR_640
397 {385,592,305-236} // GR_1024
400 {311,377,380-311},// GR_640
401 {507,592,380-311} // GR_1024
404 {274,424,343-274},// GR_640
405 {446,667,343-274} // GR_1024
408 {437,330,506-437},// GR_640
409 {707,517,506-437} // GR_1024
412 {399,377,468-399},// GR_640
413 {646,592,468-399} // GR_1024
416 {474,377,543-474},// GR_640
417 {768,592,543-474} // GR_1024
420 {437,424,506-437},// GR_640
421 {707,667,506-437} // GR_1024
425 // avail ship list data
426 #define MULTI_TS_AVAIL_MAX_DISPLAY 4
427 static int Multi_ts_avail_coords[MULTI_TS_AVAIL_MAX_DISPLAY][GR_NUM_RESOLUTIONS][2] = { // x,y coords
445 int Multi_ts_avail_start = 0; // starting index of where we will display the available ships
446 int Multi_ts_avail_count = 0; // the # of available ship classes
448 // ship information stuff
449 #define MULTI_TS_SHIP_INFO_MAX_LINE_LEN 150
450 #define MULTI_TS_SHIP_INFO_MAX_LINES 10
451 #define MULTI_TS_SHIP_INFO_MAX_TEXT (MULTI_TS_SHIP_INFO_MAX_LINE_LEN * MULTI_TS_SHIP_INFO_MAX_LINES)
453 static int Multi_ts_ship_info_coords[GR_NUM_RESOLUTIONS][3] = {
462 char Multi_ts_ship_info_lines[MULTI_TS_SHIP_INFO_MAX_LINES][MULTI_TS_SHIP_INFO_MAX_LINE_LEN];
463 char Multi_ts_ship_info_text[MULTI_TS_SHIP_INFO_MAX_TEXT];
464 int Multi_ts_ship_info_line_count;
467 static int Multi_ts_status_coords[GR_NUM_RESOLUTIONS][3] = {
476 int Multi_ts_status_bar_mode = 0;
478 // carried icon information
479 int Multi_ts_carried_flag = 0;
480 int Multi_ts_clicked_flag = 0;
481 int Multi_ts_clicked_x,Multi_ts_clicked_y;
482 int Multi_ts_carried_ship_class;
483 int Multi_ts_carried_from_type = 0;
484 int Multi_ts_carried_from_index = 0;
486 // selected ship types (for informational purposes)
487 int Multi_ts_select_type = -1;
488 int Multi_ts_select_index = -1;
489 int Multi_ts_select_ship_class = -1;
491 // per-frame mouse hotspot vars
492 int Multi_ts_hotspot_type = -1;
493 int Multi_ts_hotspot_index = -1;
496 #define TS_GRAB_FROM_LIST 0
497 #define TS_SWAP_LIST_SLOT 1
498 #define TS_SWAP_SLOT_SLOT 2
499 #define TS_DUMP_TO_LIST 3
500 #define TS_SWAP_PLAYER_PLAYER 4
501 #define TS_MOVE_PLAYER 5
504 #define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
505 #define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team
508 #define MULTI_TS_FLAG_NONE -2 // slot is _always_ empty
509 #define MULTI_TS_FLAG_EMPTY -1 // flag is temporarily empty
510 typedef struct ts_team_data {
511 int multi_ts_objnum[MULTI_TS_NUM_SHIP_SLOTS]; // objnums for all slots in this team
512 net_player *multi_ts_player[MULTI_TS_NUM_SHIP_SLOTS]; // net players corresponding to the same slots
513 int multi_ts_flag[MULTI_TS_NUM_SHIP_SLOTS]; // flags indicating the "status" of a slot
514 int multi_players_locked; // are the players locked into place
516 ts_team_data Multi_ts_team[MULTI_TS_MAX_TEAMS]; // data for all teams
518 // deleted ship objnums
519 int Multi_ts_deleted_objnums[MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
520 int Multi_ts_num_deleted;
524 // ------------------------------------------------------------------------------------------------------
525 // TEAM SELECT FORWARD DECLARATIONS
528 // check for button presses
529 void multi_ts_check_buttons();
531 // act on a button press
532 void multi_ts_button_pressed(int n);
534 // initialize all screen data, etc
535 void multi_ts_init_graphics();
537 // blit all of the icons representing all wings
538 void multi_ts_blit_wings();
540 // blit all of the player callsigns under the correct ships
541 void multi_ts_blit_wing_callsigns();
543 // blit the ships on the avail list
544 void multi_ts_blit_avail_ships();
546 // initialize the snazzy menu stuff for dragging ships,players around
547 void multi_ts_init_snazzy();
549 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
550 int multi_ts_region_type(int region);
552 // convert the region num to a ship slot index
553 int multi_ts_slot_index(int region);
555 // convert the region num to an avail list index
556 int multi_ts_avail_index(int region);
558 // convert the region num to a player slot index
559 int multi_ts_player_index(int region);
561 // blit the status bar
562 void multi_ts_blit_status_bar();
564 // assign the correct players to the correct slots
565 void multi_ts_init_players();
567 // assign the correct objnums to the correct slots
568 void multi_ts_init_objnums();
570 // assign the correct flags to the correct slots
571 void multi_ts_init_flags();
573 // get the proper team and slot index for the given ship name
574 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index);
576 // handle an available ship scroll down button press
577 void multi_ts_avail_scroll_down();
579 // handle an available ship scroll up button press
580 void multi_ts_avail_scroll_up();
582 // handle all mouse events (clicking, dragging, and dropping)
583 void multi_ts_handle_mouse();
585 // can the specified player perform the action he is attempting
586 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index = -1);
588 // determine the kind of drag and drop operation this is
589 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index = -1);
591 // swap two player positions
592 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index = -1);
595 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index = -1);
597 // get the ship class of the current index in the avail list or -1 if none exists
598 int multi_ts_get_avail_ship_class(int index);
600 // blit the currently carried icon (if any)
601 void multi_ts_blit_carried_icon();
603 // if the (console) player is allowed to grab a player slot at this point
604 int multi_ts_can_grab_player(int slot_index,int player_index = -1);
606 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
607 int multi_ts_slot_bmap_num(int slot_index);
609 // blit any active ship information text
610 void multi_ts_blit_ship_info();
612 // select the given slot and setup any information, etc
613 void multi_ts_select_ship();
615 // is it ok for this player to commit
616 int multi_ts_ok_to_commit();
618 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
619 int multi_ts_avail_bmap_num(int slot_index);
621 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
622 void multi_ts_set_status_bar_mode(int m);
624 // check to see that no illegal ship settings have occurred
625 void multi_ts_check_errors();
627 // ------------------------------------------------------------------------------------------------------
628 // TEAM SELECT FUNCTIONS
631 // initialize the team select screen (always call, even when switching between weapon select, etc)
634 // if we haven't initialized at all yet, then do it
635 if(!Multi_ts_inited){
636 multi_ts_init_graphics();
640 // use the common interface palette
641 multi_common_set_palette();
643 // set the interface palette
644 // common_set_interface_palette(MULTI_TS_PALETTE);
646 Net_player->state = NETPLAYER_STATE_SHIP_SELECT;
648 Current_screen = ON_SHIP_SELECT;
651 // initialize all critical internal data structures
652 void multi_ts_common_init()
656 // reset timestamps here. they seem to get hosed by the loadinh of the mission file
657 multi_reset_timestamps();
659 // saying "not allowed to mess with ships"
660 Multi_ts_status_bar_mode = 0;
662 // intialize ship info stuff
663 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
664 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
665 Multi_ts_ship_info_line_count = 0;
667 // initialize carried icon information
668 Multi_ts_carried_flag = 0;
669 Multi_ts_clicked_flag = 0;
670 Multi_ts_clicked_x = 0;
671 Multi_ts_clicked_y = 0;
672 Multi_ts_carried_ship_class = -1;
673 Multi_ts_carried_from_type = 0;
674 Multi_ts_carried_from_index = 0;
676 // selected slot information (should be default player ship)
677 if(!MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
678 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
679 Multi_ts_select_index = Net_player->p_info.ship_index;
681 // select this ship and setup his info
682 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
683 multi_ts_select_ship();
685 Multi_ts_select_type = -1;
686 Multi_ts_select_index = -1;
688 // no ship class selected for information purposes
689 Multi_ts_select_ship_class = -1;
692 // deleted ship information
693 memset(Multi_ts_deleted_objnums,0,sizeof(int) * MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS);
694 Multi_ts_num_deleted = 0;
696 // mouse hotspot information
697 Multi_ts_hotspot_type = -1;
698 Multi_ts_hotspot_index = -1;
700 // initialize avail ship list data
701 Multi_ts_avail_start = 0;
703 // load the locked button bitmaps bitmaps
704 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
705 Multi_ts_locked_bitmaps[idx] = -1;
706 Multi_ts_locked_bitmaps[idx] = bm_load(Multi_ts_bmap_names[gr_screen.res][idx]);
709 // blast the team data clean
710 memset(Multi_ts_team,0,sizeof(ts_team_data) * MULTI_TS_MAX_TEAMS);
712 // assign the correct players to the correct slots
713 multi_ts_init_players();
715 // assign the correct objnums to the correct slots
716 multi_ts_init_objnums();
718 // sync the interface as normal
719 multi_ts_sync_interface();
722 // do frame for team select
725 int k = chatbox_process();
726 k = Multi_ts_window.process(k);
728 // process any keypresses
731 gamesnd_play_iface(SND_USER_SELECT);
732 multi_quit_game(PROMPT_ALL);
735 // cycle to the weapon select screen
737 gamesnd_play_iface(SND_USER_SELECT);
738 Next_screen = ON_WEAPON_SELECT;
739 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
742 case KEY_ENTER|KEY_CTRLED:
743 multi_ts_commit_pressed();
747 // check any button presses
748 multi_ts_check_buttons();
750 // handle all mouse related events
751 multi_ts_handle_mouse();
754 multi_ts_check_errors();
756 // draw the background, etc
758 GR_MAYBE_CLEAR_RES(Multi_ts_bitmap);
759 if(Multi_ts_bitmap != -1){
760 gr_set_bitmap(Multi_ts_bitmap);
763 Multi_ts_window.draw();
766 multi_ts_blit_wings();
768 // blit all callsigns
769 multi_ts_blit_wing_callsigns();
771 // blit the ships on the available list
772 multi_ts_blit_avail_ships();
774 // force draw the ship select button
775 Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button.draw_forced(2);
777 // force draw the "locked" button if necessary
778 if(multi_ts_is_locked()){
779 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(2);
781 if( ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) ||
782 ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST)) ){
783 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(0);
785 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw();
789 // blit any active ship information
790 multi_ts_blit_ship_info();
792 // blit the status bar
793 multi_ts_blit_status_bar();
795 // render the chatbox
799 Multi_ts_window.draw_tooltip();
801 // display the status of the voice system
802 multi_common_voice_display_status();
804 // blit any carried icons
805 multi_ts_blit_carried_icon();
811 // close the team select screen (always call, even when switching between weapon select, etc)
812 void multi_ts_close()
816 if(!Multi_ts_inited){
822 // shut down the snazzy menu
825 // unload any bitmaps
826 if(!bm_unload(Multi_ts_bitmap)){
827 nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ts_bitmap_fname[gr_screen.res]));
829 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
830 if(Multi_ts_locked_bitmaps[idx] != -1){
831 bm_release(Multi_ts_locked_bitmaps[idx]);
832 Multi_ts_locked_bitmaps[idx] = -1;
836 // destroy the UI_WINDOW
837 Multi_ts_window.destroy();
840 // is the given slot disabled for the specified player
841 int multi_ts_disabled_slot(int slot_num, int player_index)
845 // get the appropriate net player
846 if(player_index == -1){
849 pl = &Net_players[player_index];
852 // if the player is an observer, its _always_ disabled
853 if(pl->flags & NETINFO_FLAG_OBSERVER){
857 // if the flag for this team isn't set to "free" we can't do anything
858 if(!Multi_ts_team[pl->p_info.team].multi_players_locked){
862 // if the "leaders" only flag is set
863 if(Netgame.options.flags & MSO_FLAG_SS_LEADERS){
864 // in a team vs. team situation
865 if(Netgame.type_flags & NG_TYPE_TEAM){
866 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
870 // in a non team vs. team situation
872 if(pl->flags & NETINFO_FLAG_GAME_HOST){
877 // in a team vs. team situation
878 if(Netgame.type_flags & NG_TYPE_TEAM){
879 // if i'm the team captain I can mess with my own ships as well as those of the ai ships on my team
880 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
881 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)){
888 // in a non team vs. team situation
890 // if we're the host, we can our own ship and ai ships
891 if(pl->flags & NETINFO_FLAG_GAME_HOST){
892 // can't grab player ships
893 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)){
901 // if this is our slot, then we can grab it
902 if(slot_num == pl->p_info.ship_index){
910 // is the given slot disabled for the specified player, _and_ it is his ship as well
911 int multi_ts_disabled_high_slot(int slot_index,int player_index)
915 // get the appropriate net player
916 if(player_index == -1){
919 pl = &Net_players[player_index];
922 // if this is disabled for him and its also _his_ slot
923 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)){
930 // resynch all display/interface elements based upon all the ship/weapon pool values
931 void multi_ts_sync_interface()
935 // item 1 - determine how many ship types are available in the ship pool
936 Multi_ts_avail_count = 0;
937 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
938 if(Ss_pool[idx] > 0){
939 Multi_ts_avail_count++;
943 // item 2 - make sure our local Multi_ts_slot_flag array is up to date
944 multi_ts_init_flags();
946 // item 3 - set/unset any necessary flags in underlying ship select data structures
947 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
948 switch(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx]){
949 case MULTI_TS_FLAG_EMPTY :
950 ss_make_slot_empty(idx);
952 case MULTI_TS_FLAG_NONE :
955 ss_make_slot_full(idx);
960 // item 4 - reset the locked/unlocked status of all ships in the weapon select screen
961 ss_recalc_multiplayer_slots();
964 void multi_ts_assign_players_all()
966 int idx,team_index,slot_index,found,player_count,shipnum;
967 char name_lookup[100];
970 // set all player ship indices to -1
971 for(idx=0;idx<MAX_PLAYERS;idx++){
972 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
973 Net_players[idx].p_info.ship_index = -1;
977 // merge the created object list with the actual object list so we have all available ships
978 obj_merge_created_list();
980 // get the # of players currently in the game
981 player_count = multi_num_players();
983 // always assign the host to Alpha 1 (or Zeta 1 in team vs. team - as appropriate)
984 memset(name_lookup,0,100);
985 if(Netgame.type_flags & NG_TYPE_TEAM){
986 switch(Netgame.host->p_info.team){
988 strcpy(name_lookup,NOX("alpha 1"));
991 strcpy(name_lookup,NOX("zeta 1"));
995 strcpy(name_lookup,NOX("alpha 1"));
997 shipnum = ship_name_lookup(name_lookup);
999 // if we couldn't find the ship for the host
1001 // Netgame.flags |= NG_FLAG_QUITTING;
1002 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1006 multi_ts_get_team_and_slot(Ships[shipnum].ship_name,&team_index,&slot_index);
1007 multi_assign_player_ship(NET_PLAYER_INDEX(Netgame.host),&Objects[Ships[shipnum].objnum],Ships[shipnum].ship_info_index);
1008 Netgame.host->p_info.ship_index = slot_index;
1009 Assert(Netgame.host->p_info.ship_index >= 0);
1010 Netgame.host->p_info.ship_class = Ships[shipnum].ship_info_index;
1011 Netgame.host->player->objnum = Ships[shipnum].objnum;
1013 // for each netplayer, try and find a ship
1014 objp = GET_FIRST(&obj_used_list);
1015 while(objp != END_OF_LIST(&obj_used_list)){
1016 // find a valid player ship - ignoring the ship which was assigned to the host
1017 if((objp->flags & OF_PLAYER_SHIP) && stricmp(Ships[objp->instance].ship_name,name_lookup)){
1018 // determine what team and slot this ship is
1019 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1020 Assert((team_index != -1) && (slot_index != -1));
1022 // in a team vs. team situation
1023 if(Netgame.type_flags & NG_TYPE_TEAM){
1024 // find a player on this team who needs a ship
1026 for(idx=0;idx<MAX_PLAYERS;idx++){
1027 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)){
1033 // in a non team vs. team situation
1035 // find any player on this who needs a ship
1037 for(idx=0;idx<MAX_PLAYERS;idx++){
1038 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1)){
1045 // if we found a player
1047 multi_assign_player_ship(idx,objp,Ships[objp->instance].ship_info_index);
1048 Net_players[idx].p_info.ship_index = slot_index;
1049 Assert(Net_players[idx].p_info.ship_index >= 0);
1050 Net_players[idx].p_info.ship_class = Ships[objp->instance].ship_info_index;
1051 Net_players[idx].player->objnum = OBJ_INDEX(objp);
1053 // decrement the player count
1056 objp->flags &= ~OF_PLAYER_SHIP;
1057 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1060 // if we've assigned all players, we're done
1061 if(player_count <= 0){
1066 // move to the next item
1067 objp = GET_NEXT(objp);
1070 // go through and change any ships marked as player ships to be COULD_BE_PLAYER
1071 if ( objp != END_OF_LIST(&obj_used_list) ) {
1072 for ( objp = GET_NEXT(objp); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1073 if ( objp->flags & OF_PLAYER_SHIP ){
1074 objp->flags &= ~OF_PLAYER_SHIP;
1075 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1080 if(Game_mode & GM_STANDALONE_SERVER){
1082 Net_player->player->objnum = -1;
1085 // check to make sure all players were assigned correctly
1086 for(idx=0;idx<MAX_PLAYERS;idx++){
1087 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
1088 // if this guy never got assigned a player ship, there's a mission problem
1089 if(Net_players[idx].p_info.ship_index == -1){
1090 // Netgame.flags |= NG_FLAG_QUITTING;
1091 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1098 // delete ships which have been removed from the game, tidy things
1099 void multi_ts_create_wings()
1103 // the standalone never went through this screen so he should never call this function!
1104 // the standalone and all other clients will have this equivalent function performed whey they receieve
1105 // the post_sync_data_packet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1106 Assert(!(Game_mode & GM_STANDALONE_SERVER));
1108 // check status of all ships and delete or change ship type as necessary
1109 Multi_ts_num_deleted = 0;
1110 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1111 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1112 // otherwise if there's a valid ship in this spot
1113 if(Multi_ts_team[idx].multi_ts_flag[s_idx] >= 0){
1116 // set the ship type appropriately
1117 Assert(Wss_slots_teams[idx][s_idx].ship_class >= 0);
1119 objnum = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1120 change_ship_type(Objects[objnum].instance,Wss_slots_teams[idx][s_idx].ship_class);
1122 // set the ship weapons correctly
1123 wl_update_ship_weapons(objnum,&Wss_slots_teams[idx][s_idx]);
1125 // assign ts_index of the ship to point to the proper Wss_slots slot
1126 Ships[Objects[objnum].instance].ts_index = s_idx;
1127 } else if(Multi_ts_team[idx].multi_ts_flag[s_idx] == MULTI_TS_FLAG_EMPTY){
1128 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] >= 0);
1130 // mark the object as having been deleted
1131 Multi_ts_deleted_objnums[Multi_ts_num_deleted] = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1134 ship_add_exited_ship( &Ships[Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance], SEF_PLAYER_DELETED );
1135 obj_delete(Multi_ts_deleted_objnums[Multi_ts_num_deleted]);
1136 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]);
1138 // increment the # of ships deleted
1139 Multi_ts_num_deleted++;
1145 // do any necessary processing for players who have left the game
1146 void multi_ts_handle_player_drop()
1151 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1152 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1153 // if we found him, clear his player slot and set his object back to being OF_COULD_BE_PLAYER
1154 if((Multi_ts_team[idx].multi_ts_player[s_idx] != NULL) && !MULTI_CONNECTED((*Multi_ts_team[idx].multi_ts_player[s_idx]))){
1155 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1);
1156 Multi_ts_team[idx].multi_ts_player[s_idx] = NULL;
1157 Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags &= ~(OF_PLAYER_SHIP);
1158 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);
1164 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
1165 void multi_ts_set_status_bar_mode(int m)
1167 Multi_ts_status_bar_mode = m;
1170 // blit the proper "locked" button - used for weapon select and briefing screens
1171 void multi_ts_blit_locked_button()
1173 // if we're locked down and we have a valid bitmap
1174 if((Multi_ts_team[Net_player->p_info.team].multi_players_locked) && (Multi_ts_locked_bitmaps[2] != -1)){
1175 gr_set_bitmap(Multi_ts_locked_bitmaps[2]);
1176 gr_bitmap(Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1178 // draw as "not locked" if possible
1179 else if(Multi_ts_locked_bitmaps[0] != -1){
1180 gr_set_bitmap(Multi_ts_locked_bitmaps[0]);
1181 gr_bitmap( Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1185 // the "lock" button has been pressed
1186 void multi_ts_lock_pressed()
1188 // do nothing if the button has already been pressed
1189 if(multi_ts_is_locked()){
1190 gamesnd_play_iface(SND_GENERAL_FAIL);
1194 if(Netgame.type_flags & NG_TYPE_TEAM){
1195 Assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
1197 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1199 gamesnd_play_iface(SND_USER_SELECT);
1201 // send a final player slot update packet
1202 send_pslot_update_packet(Net_player->p_info.team,TS_CODE_LOCK_TEAM,-1);
1203 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
1205 // sync interface stuff
1206 multi_ts_set_status_bar_mode(1);
1207 multi_ts_sync_interface();
1208 ss_recalc_multiplayer_slots();
1210 // disable this button now
1211 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1215 int multi_ts_is_locked()
1217 return Multi_ts_team[Net_player->p_info.team].multi_players_locked;
1220 // show a popup saying "only host and team captains can modify, etc, etc"
1221 void multi_ts_maybe_host_only_popup()
1224 // if this is because the "host modifies" option is set
1225 if((Netgame.options.flags & MSO_FLAG_SS_LEADERS) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1226 multi_ts_host_only_popup();
1229 if(Netgame.type == NG_TYPE_TEAM){
1230 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only team captains may modify ships and weapons in this game");
1232 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only the host may modify ships and weapons in this game");
1238 // ------------------------------------------------------------------------------------------------------
1239 // TEAM SELECT FORWARD DEFINITIONS
1242 // check for button presses
1243 void multi_ts_check_buttons()
1246 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1247 // we only really need to check for one button pressed at a time, so we can break after
1249 if(Multi_ts_buttons[gr_screen.res][idx].button.pressed()){
1250 multi_ts_button_pressed(idx);
1256 // act on a button press
1257 void multi_ts_button_pressed(int n)
1260 // back to the briefing screen
1261 case MULTI_TS_BRIEFING :
1262 gamesnd_play_iface(SND_USER_SELECT);
1263 Next_screen = ON_BRIEFING_SELECT;
1264 gameseq_post_event( GS_EVENT_START_BRIEFING );
1266 // already on this screen
1267 case MULTI_TS_SHIP_SELECT:
1268 gamesnd_play_iface(SND_GENERAL_FAIL);
1270 // back to the weapon select screen
1271 case MULTI_TS_WEAPON_SELECT:
1272 gamesnd_play_iface(SND_USER_SELECT);
1273 Next_screen = ON_WEAPON_SELECT;
1274 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
1276 // scroll the available ships list down
1277 case MULTI_TS_SHIPS_DOWN:
1278 multi_ts_avail_scroll_down();
1280 // scroll the available ships list up
1281 case MULTI_TS_SHIPS_UP:
1282 multi_ts_avail_scroll_up();
1284 // free ship/weapon select
1286 Assert(Game_mode & GM_MULTIPLAYER);
1287 // the "lock" button has been pressed
1288 multi_ts_lock_pressed();
1290 // disable the button if it is now locked
1291 if(multi_ts_is_locked()){
1292 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1296 case MULTI_TS_COMMIT :
1297 multi_ts_commit_pressed();
1300 gamesnd_play_iface(SND_GENERAL_FAIL);
1305 // initialize all screen data, etc
1306 void multi_ts_init_graphics()
1310 // create the interface window
1311 Multi_ts_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
1312 Multi_ts_window.set_mask_bmap(Multi_ts_bitmap_mask_fname[gr_screen.res]);
1314 // load the background bitmap
1315 Multi_ts_bitmap = bm_load(Multi_ts_bitmap_fname[gr_screen.res]);
1316 if(Multi_ts_bitmap < 0){
1317 // we failed to load the bitmap - this is very bad
1321 // create the interface buttons
1322 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1323 // create the object
1324 if((idx == MULTI_TS_SHIPS_UP) || (idx == MULTI_TS_SHIPS_DOWN)){
1325 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);
1327 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);
1330 // set the sound to play when highlighted
1331 Multi_ts_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1333 // set the ani for the button
1334 Multi_ts_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ts_buttons[gr_screen.res][idx].filename);
1337 Multi_ts_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ts_buttons[gr_screen.res][idx].hotspot);
1341 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);
1342 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);
1343 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);
1344 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);
1345 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);
1347 // 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);
1348 // 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);
1352 // make the ship scrolling lists
1354 // if we're not the host of the game (or a tema captain in team vs. team mode), disable the lock button
1355 if (Netgame.type_flags & NG_TYPE_TEAM) {
1356 if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1357 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1360 if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1361 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1365 // initialize the snazzy menu stuff (for grabbing ships, names, etc)
1366 multi_ts_init_snazzy();
1368 // create the chatbox (again, should not be necessary at this point)
1371 // sync the interface as normal
1372 multi_ts_sync_interface();
1375 // blit all of the icons representing all wings
1376 void multi_ts_blit_wings()
1380 // blit them all blindly for now
1381 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1382 // if this ship doesn't exist, then continue
1383 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1387 // otherwise blit the ship icon or the "empty" icon
1388 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY){
1389 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);
1391 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));
1393 // if this is a team vs team game, and the slot is occupised by a team captain, put a c there
1394 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)){
1395 gr_set_color_fast(&Color_bright);
1396 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 ]]
1402 // blit all of the player callsigns under the correct ships
1403 void multi_ts_blit_wing_callsigns()
1406 char callsign[CALLSIGN_LEN+2];
1409 // blit them all blindly for now
1410 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1411 // if this ship doesn't exist, then continue
1412 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1416 // if there is a player in the slot
1417 if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
1418 // make sure the string fits
1419 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->player->callsign);
1421 // determine if this is a locked AI ship
1422 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
1423 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
1424 strcpy(callsign, NOX("<"));
1425 strcat(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1426 strcat(callsign, NOX(">"));
1428 strcpy(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1432 gr_force_fit_string(callsign, CALLSIGN_LEN, Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD]);
1434 // get the final length
1435 gr_get_string_size(&callsign_w, NULL, callsign);
1438 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)){
1439 gr_set_color_fast(&Color_text_active_hi);
1441 gr_set_color_fast(&Color_normal);
1443 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);
1447 // blit the ships on the avail list
1448 void multi_ts_blit_avail_ships()
1450 int display_count,ship_count,idx;
1453 // blit the availability of all ship counts
1456 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
1457 if(Ss_pool[idx] > 0){
1458 // if our starting display index is after this, then skip it
1459 if(ship_count < Multi_ts_avail_start){
1463 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));
1465 // blit the ship count available
1466 sprintf(count,"%d",Ss_pool[idx]);
1467 gr_set_color_fast(&Color_normal);
1468 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);
1470 // increment the counts
1476 // if we've reached the max amount we can display, then stop
1477 if(display_count >= MULTI_TS_AVAIL_MAX_DISPLAY){
1483 // initialize the snazzy menu stuff for dragging ships,players around
1484 void multi_ts_init_snazzy()
1486 // initialize the snazzy menu
1490 Multi_ts_snazzy_regions = 0;
1491 memset(Multi_ts_region,0,sizeof(MENU_REGION) * MULTI_TS_NUM_SNAZZY_REGIONS);
1493 // get a pointer to the mask bitmap data
1494 Multi_ts_mask_data = (ubyte*)Multi_ts_window.get_mask_data(&Multi_ts_mask_w, &Multi_ts_mask_h);
1496 // add the wing slots information
1497 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_0, 0);
1498 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_1, 0);
1499 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_2, 0);
1500 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_3, 0);
1501 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_0, 0);
1502 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_1, 0);
1503 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_2, 0);
1504 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_3, 0);
1505 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_0, 0);
1506 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_1, 0);
1507 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_2, 0);
1508 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_3, 0);
1510 // add the name slots information
1511 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_0, 0);
1512 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_1, 0);
1513 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_2, 0);
1514 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_3, 0);
1515 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_0, 0);
1516 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_1, 0);
1517 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_2, 0);
1518 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_3, 0);
1519 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_0, 0);
1520 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_1, 0);
1521 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_2, 0);
1522 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_3, 0);
1524 // add the available ships region
1525 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_0, 0);
1526 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_1, 0);
1527 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_2, 0);
1528 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_3, 0);
1531 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
1532 int multi_ts_region_type(int region)
1534 if((region == TSWING_0_SHIP_0) || (region == TSWING_0_SHIP_1) || (region == TSWING_0_SHIP_2) || (region == TSWING_0_SHIP_3) ||
1535 (region == TSWING_1_SHIP_0) || (region == TSWING_1_SHIP_1) || (region == TSWING_1_SHIP_2) || (region == TSWING_1_SHIP_3) ||
1536 (region == TSWING_2_SHIP_0) || (region == TSWING_2_SHIP_1) || (region == TSWING_2_SHIP_2) || (region == TSWING_2_SHIP_3) ){
1537 return MULTI_TS_SLOT_LIST;
1540 if((region == TSWING_0_NAME_0) || (region == TSWING_0_NAME_1) || (region == TSWING_0_NAME_2) || (region == TSWING_0_NAME_3) ||
1541 (region == TSWING_1_NAME_0) || (region == TSWING_1_NAME_1) || (region == TSWING_1_NAME_2) || (region == TSWING_1_NAME_3) ||
1542 (region == TSWING_2_NAME_0) || (region == TSWING_2_NAME_1) || (region == TSWING_2_NAME_2) || (region == TSWING_2_NAME_3) ){
1543 return MULTI_TS_PLAYER_LIST;
1546 if((region == TSWING_LIST_0) || (region == TSWING_LIST_1) || (region == TSWING_LIST_2) || (region == TSWING_LIST_3)){
1547 return MULTI_TS_AVAIL_LIST;
1553 // convert the region num to a ship slot index
1554 int multi_ts_slot_index(int region)
1557 case TSWING_0_SHIP_0:
1559 case TSWING_0_SHIP_1:
1561 case TSWING_0_SHIP_2:
1563 case TSWING_0_SHIP_3:
1565 case TSWING_1_SHIP_0:
1567 case TSWING_1_SHIP_1:
1569 case TSWING_1_SHIP_2:
1571 case TSWING_1_SHIP_3:
1573 case TSWING_2_SHIP_0:
1575 case TSWING_2_SHIP_1:
1577 case TSWING_2_SHIP_2:
1579 case TSWING_2_SHIP_3:
1586 // convert the region num to an avail list index (starting from absolute 0)
1587 int multi_ts_avail_index(int region)
1603 // convert the region num to a player slot index
1604 int multi_ts_player_index(int region)
1607 case TSWING_0_NAME_0:
1609 case TSWING_0_NAME_1:
1611 case TSWING_0_NAME_2:
1613 case TSWING_0_NAME_3:
1615 case TSWING_1_NAME_0:
1617 case TSWING_1_NAME_1:
1619 case TSWING_1_NAME_2:
1621 case TSWING_1_NAME_3:
1623 case TSWING_2_NAME_0:
1625 case TSWING_2_NAME_1:
1627 case TSWING_2_NAME_2:
1629 case TSWING_2_NAME_3:
1636 // blit any active ship information text
1637 void multi_ts_blit_ship_info()
1643 // if we don't have a valid ship selected, do nothing
1644 if(Multi_ts_select_ship_class == -1){
1648 // get the ship class
1649 sip = &Ship_info[Multi_ts_select_ship_class];
1652 y_start = Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_Y_COORD];
1656 // blit the ship class (name)
1657 gr_set_color_fast(&Color_normal);
1658 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Class",739));
1659 if(strlen(sip->name)){
1660 gr_set_color_fast(&Color_bright);
1661 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->name);
1665 // blit the ship type
1666 gr_set_color_fast(&Color_normal);
1667 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Type",740));
1668 if((sip->type_str != NULL) && strlen(sip->type_str)){
1669 gr_set_color_fast(&Color_bright);
1670 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->type_str);
1674 // blit the ship length
1675 gr_set_color_fast(&Color_normal);
1676 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Length",741));
1677 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1678 gr_set_color_fast(&Color_bright);
1679 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->ship_length);
1683 // blit the max velocity
1684 gr_set_color_fast(&Color_normal);
1685 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Max Velocity",742));
1686 sprintf(str,XSTR("%d m/s",743),(int)sip->max_vel.z);
1687 gr_set_color_fast(&Color_bright);
1688 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,str);
1691 // blit the maneuverability
1692 gr_set_color_fast(&Color_normal);
1693 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Maneuverability",744));
1694 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1695 gr_set_color_fast(&Color_bright);
1696 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->maneuverability_str);
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("Armor",745));
1703 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
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->armor_str);
1709 // blit the gun mounts
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("Gun Mounts",746));
1712 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
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->gun_mounts);
1718 // blit the missile banke
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("Missile Banks",747));
1721 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
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->missile_banks);
1727 // blit the manufacturer
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("Manufacturer",748));
1730 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
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,sip->manufacturer_str);
1736 // blit the _short_ text description
1738 Assert(Multi_ts_ship_info_line_count < 3);
1739 gr_set_color_fast(&Color_normal);
1740 for(idx=0;idx<Multi_ts_ship_info_line_count;idx++){
1741 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, Multi_ts_ship_info_lines[idx]);
1748 // blit the status bar
1749 void multi_ts_blit_status_bar()
1755 // mode specific text
1756 switch(Multi_ts_status_bar_mode){
1758 strcpy(text,XSTR("Ships/Weapons Locked",749));
1762 strcpy(text,XSTR("Ships/Weapons Are Now Free",750));
1767 // if we should be blitting
1769 gr_get_string_size(&text_w,NULL,text);
1770 gr_set_color_fast(&Color_bright_blue);
1771 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);
1775 // assign the correct players to the correct slots
1776 void multi_ts_init_players()
1780 // if i'm an observer, i have no ship
1781 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1782 Net_player->p_info.ship_index = -1;
1785 // initialize all players and observer
1786 for(idx=0;idx<MAX_PLAYERS;idx++){
1787 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1788 if(MULTI_OBSERVER(Net_players[idx])){
1789 Net_players[idx].p_info.ship_index = -1;
1791 Multi_ts_team[Net_players[idx].p_info.team].multi_ts_player[Net_players[idx].p_info.ship_index] = &Net_players[idx];
1797 // assign the correct objnums to the correct slots
1798 void multi_ts_init_objnums()
1800 int idx,s_idx,team_index,slot_index;
1803 // zero out the indices
1804 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1805 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1806 Multi_ts_team[idx].multi_ts_objnum[s_idx] = -1;
1810 // set all the objnums
1811 objp = GET_FIRST(&obj_used_list);
1812 while(objp != END_OF_LIST(&obj_used_list)){
1813 // if its a ship, get its slot index (if any)
1814 if(objp->type == OBJ_SHIP){
1815 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1816 if((slot_index != -1) && (team_index != -1)){
1817 Multi_ts_team[team_index].multi_ts_objnum[slot_index] = Ships[objp->instance].objnum;
1821 objp = GET_NEXT(objp);
1825 // get the proper team and slot index for the given ship name
1826 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index)
1830 // set the return values to default values
1834 // if we're in team vs. team mode
1835 if(Netgame.type_flags & NG_TYPE_TEAM){
1836 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1837 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1838 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
1840 *slot_index = s_idx;
1846 // if we're _not_ in team vs. team mode
1848 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1849 if(!stricmp(ship_name,Multi_ts_slot_names[idx])){
1858 // function to return the shipname of the ship in the slot designated by the team and slot
1860 char *multi_ts_get_shipname( int team, int slot_index )
1862 if ( Netgame.type_flags & NG_TYPE_TEAM ) {
1863 Assert( (team >= 0) && (team < MULTI_TS_MAX_TEAMS) );
1864 return Multi_ts_slot_team_names[team][slot_index];
1866 Assert( team == 0 );
1867 return Multi_ts_slot_names[slot_index];
1871 // assign the correct flags to the correct slots
1872 void multi_ts_init_flags()
1876 // zero out the flags
1877 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1878 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1879 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_NONE;
1883 // in a team vs. team situation
1884 if(Netgame.type_flags & NG_TYPE_TEAM){
1885 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1886 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1887 // if the there is an objnum here but no ship class, we know its currently empty
1888 if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class == -1)){
1889 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_EMPTY;
1890 } else if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class != -1)){
1891 Multi_ts_team[idx].multi_ts_flag[s_idx] = Wss_slots_teams[idx][s_idx].ship_class;
1896 // in a non team vs. team situation
1898 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1899 // if the there is an objnum here but no ship class, we know its currently empty
1900 if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class == -1)){
1901 Multi_ts_team[0].multi_ts_flag[idx] = MULTI_TS_FLAG_EMPTY;
1902 } else if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class != -1)){
1903 Multi_ts_team[0].multi_ts_flag[idx] = Wss_slots[idx].ship_class;
1909 // handle an available ship scroll down button press
1910 void multi_ts_avail_scroll_down()
1912 if((Multi_ts_avail_count - Multi_ts_avail_start) > MULTI_TS_AVAIL_MAX_DISPLAY){
1913 gamesnd_play_iface(SND_USER_SELECT);
1914 Multi_ts_avail_start++;
1916 gamesnd_play_iface(SND_GENERAL_FAIL);
1920 // handle an available ship scroll up button press
1921 void multi_ts_avail_scroll_up()
1923 if(Multi_ts_avail_start > 0){
1924 gamesnd_play_iface(SND_USER_SELECT);
1925 Multi_ts_avail_start--;
1927 gamesnd_play_iface(SND_GENERAL_FAIL);
1931 // handle all mouse events (clicking, dragging, and dropping)
1932 void multi_ts_handle_mouse()
1934 int snazzy_region,snazzy_action;
1935 int region_type,region_index,region_empty;
1936 int mouse_x,mouse_y,ship_class;
1938 // get the mouse coords
1939 mouse_get_pos(&mouse_x,&mouse_y);
1941 // do frame for the snazzy menu
1942 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);
1948 if(snazzy_region != -1){
1949 region_type = multi_ts_region_type(snazzy_region);
1950 Assert(region_type != -1);
1952 // determine what type of region the mouse is over and the appropriate index
1953 switch(region_type){
1954 case MULTI_TS_AVAIL_LIST:
1955 region_index = multi_ts_avail_index(snazzy_region);
1956 ship_class = multi_ts_get_avail_ship_class(region_index);
1958 if(ship_class == -1){
1961 region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1;
1964 case MULTI_TS_SLOT_LIST:
1965 region_index = multi_ts_slot_index(snazzy_region);
1966 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] >= 0) ? 0 : 1;
1968 ship_class = Wss_slots[region_index].ship_class;
1971 case MULTI_TS_PLAYER_LIST:
1972 region_index = multi_ts_player_index(snazzy_region);
1973 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL) ? 0 : 1;
1978 // maybe play a "highlight" sound
1979 switch(region_type){
1980 case MULTI_TS_PLAYER_LIST:
1981 if((Multi_ts_hotspot_index != region_index) && (region_index >= 0) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL)){
1982 gamesnd_play_iface(SND_USER_SELECT);
1987 // set the current frame mouse hotspot vars
1988 Multi_ts_hotspot_type = region_type;
1989 Multi_ts_hotspot_index = region_index;
1991 // if we currently have clicked on something and have just released it
1992 if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
1993 Multi_ts_clicked_flag = 0;
1996 // if we're currently not carrying anything and the user has clicked
1997 if(!Multi_ts_carried_flag && !Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && !region_empty){
1998 // set the "clicked" flag
1999 Multi_ts_clicked_flag = 1;
2001 // check to see if he clicked on a ship type and highlight if necessary
2002 switch(region_type){
2003 // selected a ship in the wing slots
2004 case MULTI_TS_SLOT_LIST:
2005 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
2006 Multi_ts_select_index = region_index;
2007 multi_ts_select_ship();
2010 // selected a ship on the avail list
2011 case MULTI_TS_AVAIL_LIST:
2012 Multi_ts_select_type = MULTI_TS_AVAIL_LIST;
2013 Multi_ts_select_index = region_index;
2014 multi_ts_select_ship();
2017 // selected something else - unselect
2019 Multi_ts_select_type = -1;
2020 Multi_ts_select_index = -1;
2021 Multi_ts_select_ship_class = -1;
2025 Multi_ts_clicked_x = mouse_x;
2026 Multi_ts_clicked_y = mouse_y;
2029 // if we had something clicked and have started dragging it
2030 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))){
2031 // if this player is an observer, he shouldn't be able to do jack
2032 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2036 // first we check for illegal conditions (any case where he cannot grab what he is attempting to grab)
2037 switch(region_type){
2038 case MULTI_TS_AVAIL_LIST :
2039 // if players are not yet locked, can't grab ships
2040 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2048 case MULTI_TS_SLOT_LIST:
2049 // if players are not yet locked, can't grab ships
2050 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2054 if(multi_ts_disabled_slot(region_index)){
2055 multi_ts_maybe_host_only_popup();
2058 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] < 0){
2062 case MULTI_TS_PLAYER_LIST:
2063 if(!multi_ts_can_grab_player(region_index)){
2070 Multi_ts_clicked_flag = 0;
2071 Multi_ts_carried_flag = 1;
2073 // set up the carried icon here
2074 Multi_ts_carried_from_type = region_type;
2075 Multi_ts_carried_from_index = region_index;
2076 Multi_ts_carried_ship_class = ship_class;
2079 // if we were carrying something but have dropped it
2080 if(Multi_ts_carried_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2081 Multi_ts_carried_flag = 0;
2082 Multi_ts_clicked_flag = 0;
2084 // if we're not allowed to drop onto this slot
2085 if((region_type == MULTI_TS_SLOT_LIST) && multi_ts_disabled_slot(region_index)){
2086 multi_ts_maybe_host_only_popup();
2089 // if we're over some kind of valid region, apply
2090 multi_ts_drop(Multi_ts_carried_from_type,Multi_ts_carried_from_index,region_type,region_index,Multi_ts_carried_ship_class);
2094 // can the specified player perform the action he is attempting
2095 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2101 // get the appropriate player
2102 if(player_index == -1){
2105 pl = &Net_players[player_index];
2108 // get the operation type
2109 op_type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2111 // if either of the indices are bogus, then bail
2112 if((from_index == -1) || (to_index == -1)){
2117 case TS_GRAB_FROM_LIST:
2118 // if there are no more of this ship class, its no go
2119 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2123 // if he's not allowed to touch the wing slot
2124 if(multi_ts_disabled_slot(to_index,player_index)){
2128 // if the slot he's trying to drop it on is "permanently" empty
2129 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2134 case TS_SWAP_LIST_SLOT:
2135 // if there are no more of this ship class, its no go
2136 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2140 // if he's not allowed to touch the wing slot
2141 if(multi_ts_disabled_slot(to_index,player_index)){
2145 // if the slot we're trying to move to is invalid, then do nothing
2146 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2150 // if the slot he's trying to drop it on is "permanently" empty
2151 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2156 case TS_SWAP_SLOT_SLOT:
2157 // if he's not allowed to touch one of the slots, its no go
2158 if(multi_ts_disabled_slot(from_index,player_index) || multi_ts_disabled_slot(to_index,player_index)){
2162 // if the slot we're taking from is invalid
2163 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2167 // if the slot he's trying to drop it on is "permanently" empty
2168 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2173 case TS_DUMP_TO_LIST:
2174 // if he's not allowed to be touching the slot to begin with, it no go
2175 if(multi_ts_disabled_slot(from_index,player_index)){
2179 // if the slot we're trying to move to is invalid, then do nothing
2180 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2185 case TS_SWAP_PLAYER_PLAYER:
2186 // if his team is already locked, he cannot do this
2187 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2191 // if there isn't a player at one of the positions
2192 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)){
2196 // if this is not a player ship type object
2197 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2198 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2199 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2204 if(Netgame.type_flags & NG_TYPE_TEAM){
2205 // if he's not the team captain, he cannot do this
2206 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2210 // if he's not the host, he cannot do this
2211 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2217 case TS_MOVE_PLAYER:
2218 // if his team is already locked, he cannot do this
2219 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2223 // if there isn't a player at the _from_
2224 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL){
2228 // if there is no ship at the _to_ location
2229 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] < 0){
2233 // if this is not a player ship type object
2234 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2235 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2236 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2241 if(Netgame.type_flags & NG_TYPE_TEAM){
2242 // if he's not the team captain, he cannot do this
2243 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2247 // if he's not the host, he cannot do this
2248 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2262 // determine the kind of drag and drop operation this is
2263 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)
2267 // get the appropriate player
2268 if(player_index == -1){
2271 pl = &Net_players[player_index];
2275 // came from the ship avail list
2276 case MULTI_TS_AVAIL_LIST :
2278 if(to_type == MULTI_TS_AVAIL_LIST){
2282 // if placing it on a slot
2283 if(to_type == MULTI_TS_SLOT_LIST){
2284 if(Wss_slots_teams[pl->p_info.team][to_index].ship_class == -1){
2285 return TS_GRAB_FROM_LIST;
2287 return TS_SWAP_LIST_SLOT;
2292 // came from the ship slots
2293 case MULTI_TS_SLOT_LIST :
2294 if(to_type == MULTI_TS_SLOT_LIST){
2295 return TS_SWAP_SLOT_SLOT;
2297 if(to_type == MULTI_TS_AVAIL_LIST){
2298 return TS_DUMP_TO_LIST;
2302 // came from the player lists
2303 case MULTI_TS_PLAYER_LIST :
2304 if(to_type == MULTI_TS_PLAYER_LIST){
2305 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL){
2306 return TS_MOVE_PLAYER;
2308 return TS_SWAP_PLAYER_PLAYER;
2317 void multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2319 int size,update,sound;
2320 ubyte wss_data[MAX_PACKET_SIZE-20];
2323 // determine what kind of operation this is
2324 int type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2326 // get the proper net player
2327 if(player_index == -1){
2330 pl = &Net_players[player_index];
2333 // set the proper pool pointers
2334 ss_set_team_pointers(pl->p_info.team);
2338 case TS_SWAP_SLOT_SLOT :
2339 nprintf(("Network","Apply swap slot slot %d %d\n",from_index,to_index));
2340 update = ss_swap_slot_slot(from_index,to_index,&sound);
2342 case TS_DUMP_TO_LIST :
2343 nprintf(("Network","Apply dump to list %d %d\n",from_index,to_index));
2344 update = ss_dump_to_list(from_index,ship_class,&sound);
2346 case TS_SWAP_LIST_SLOT :
2347 nprintf(("Network","Apply swap list slot %d %d\n",from_index,to_index));
2348 update = ss_swap_list_slot(ship_class,to_index,&sound);
2350 case TS_GRAB_FROM_LIST :
2351 nprintf(("Network","Apply grab from list %d %d\n",from_index,to_index));
2352 update = ss_grab_from_list(ship_class,to_index,&sound);
2354 case TS_SWAP_PLAYER_PLAYER :
2355 nprintf(("Network","Apply swap player player %d %d\n",from_index,to_index));
2356 update = multi_ts_swap_player_player(from_index,to_index,&sound,player_index);
2358 case TS_MOVE_PLAYER :
2359 nprintf(("Network","Apply move player %d %d\n",from_index,to_index));
2360 update = multi_ts_move_player(from_index,to_index,&sound,player_index);
2367 // if we're the host, send an update to all players
2368 if ( MULTIPLAYER_HOST ) {
2369 // send the correct type of update
2370 if(type == TS_SWAP_PLAYER_PLAYER){
2372 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound, player_index);
2373 send_wss_update_packet(pl->p_info.team,wss_data, size);
2375 // send a player slot update packet as well, so ship class information, etc is kept correct
2376 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,-1);
2379 // if the player index == -1, it means the action was done locally - so play a sound
2380 if((player_index == -1) && (sound != -1)){
2381 gamesnd_play_iface(sound);
2385 // sync the interface screen up ourselves, if necessary
2386 if(Net_player->p_info.team == pl->p_info.team){
2387 multi_ts_sync_interface();
2390 // make sure all flags are set properly for all teams
2391 multi_ts_init_flags();
2394 // set the proper pool pointers
2395 ss_set_team_pointers(Net_player->p_info.team);
2398 // drop a carried icon
2399 void multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2401 // if I'm the host, apply immediately
2402 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2403 // if this is a legal operation
2404 if(multi_ts_can_perform(from_type,from_index,to_type,to_index,ship_class,player_index)){
2405 multi_ts_apply(from_type,from_index,to_type,to_index,ship_class,player_index);
2407 nprintf(("Network","Could not apply operation!\n"));
2410 // otherwise send a request to the host
2412 send_wss_request_packet(Net_player->player_id, from_type, from_index, to_type, to_index, -1, ship_class, WSS_SHIP_SELECT);
2416 // swap two player positions
2417 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index)
2419 net_player *pl,*temp;
2421 // get the proper player pointer
2422 if(player_index == -1){
2425 pl = &Net_players[player_index];
2429 temp = Multi_ts_team[pl->p_info.team].multi_ts_player[to_index];
2430 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2431 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = temp;
2433 // update netplayer information if necessary
2434 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2435 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2436 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;
2438 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);
2440 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2441 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2442 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;
2444 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);
2447 // update ship flags
2448 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2449 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2450 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2451 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2453 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2454 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2455 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2456 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2459 // recalcalate which slots are locked/unlocked, etc
2460 ss_recalc_multiplayer_slots();
2462 // send an update packet to all players
2463 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2464 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2465 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2468 *sound = SND_ICON_DROP;
2474 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index)
2478 // get the proper player pointer
2479 if(player_index == -1){
2482 pl = &Net_players[player_index];
2486 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2487 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = NULL;
2489 // update netplayer information if necessary
2490 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2491 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2492 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;
2494 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);
2496 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2497 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2498 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;
2500 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);
2503 // update ship flags
2504 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2505 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2506 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2507 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2509 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2510 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2511 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2512 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2515 // recalcalate which slots are locked/unlocked, etc
2516 ss_recalc_multiplayer_slots();
2518 // send an update packet to all players
2519 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2520 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2521 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2524 *sound = SND_ICON_DROP;
2529 // get the ship class of the current index in the avail list or -1 if none exists
2530 int multi_ts_get_avail_ship_class(int index)
2532 int ship_count,class_index;
2534 ship_count = index + Multi_ts_avail_start;
2536 while((ship_count >= 0) && (class_index < MAX_SHIP_TYPES)){
2537 if(Ss_pool[class_index] > 0){
2541 if(ship_count >= 0){
2553 // blit the currently carried icon (if any)
2554 void multi_ts_blit_carried_icon()
2557 int offset_x,offset_y,callsign_w;
2558 char callsign[CALLSIGN_LEN+2];
2560 // if we're not carrying anything, then return
2561 if(!Multi_ts_carried_flag){
2565 // get the mouse position
2566 mouse_get_pos(&x,&y);
2568 // if we're carrying an icon of some kind
2569 switch(Multi_ts_carried_from_type){
2570 case MULTI_TS_SLOT_LIST:
2571 offset_x = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2572 offset_y = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2575 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2577 case MULTI_TS_AVAIL_LIST:
2578 offset_x = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2579 offset_y = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2582 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2584 case MULTI_TS_PLAYER_LIST:
2585 // get the final length of the string so we can calculate a valid offset
2586 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->player->callsign);
2587 gr_force_fit_string(callsign,CALLSIGN_LEN,Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD]);
2588 gr_get_string_size(&callsign_w,NULL,callsign);
2590 // calculate the offsets
2591 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);
2592 offset_y = Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2594 gr_set_color_fast(&Color_normal);
2595 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);
2602 // if the (console) player is allowed to grab a player slot at this point
2603 int multi_ts_can_grab_player(int slot_index, int player_index)
2607 // get a pointe rto the proper net player
2608 if(player_index == -1){
2611 pl = &Net_players[player_index];
2614 // if the players are locked in any case, he annot grab it
2615 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2619 if(Netgame.type_flags & NG_TYPE_TEAM){
2620 // if he's not the team captain, he cannot do this
2621 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2625 // if he's not the host, he cannot do this
2626 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2631 // if the slot is empty
2632 if(Multi_ts_team[pl->p_info.team].multi_ts_player[slot_index] == NULL){
2639 // get the team # of the given ship
2640 int multi_ts_get_team(char *ship_name)
2644 // lookup through all team ship names
2645 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
2646 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
2647 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
2653 // always on team 0 if not found otherwise
2657 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2658 int multi_ts_avail_bmap_num(int slot_index)
2660 // if this slot has been highlighted for informational purposes
2661 if((Multi_ts_select_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_select_index == slot_index)){
2662 return ICON_FRAME_SELECTED;
2665 // if its otherwise being lit by the mouse
2666 if((Multi_ts_hotspot_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_hotspot_index == slot_index)){
2667 return ICON_FRAME_HOT;
2670 return ICON_FRAME_NORMAL;
2673 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2674 int multi_ts_slot_bmap_num(int slot_index)
2676 // special case - slot is disabled, its my ship and the host hasn't locked the ships yet
2677 if(multi_ts_disabled_high_slot(slot_index)){
2678 return ICON_FRAME_DISABLED_HIGH;
2681 // if this slot is disabled for us, then show it as such
2682 if(multi_ts_disabled_slot(slot_index)){
2683 return ICON_FRAME_DISABLED;
2686 // if this slot has been highlighted for informational purposes
2687 if((Multi_ts_select_type == MULTI_TS_SLOT_LIST) && (Multi_ts_select_index == slot_index)){
2688 return ICON_FRAME_SELECTED;
2691 // if this is our ship, then highlight it as so
2692 if(Net_player->p_info.ship_index == slot_index){
2693 return ICON_FRAME_PLAYER;
2696 // if its otherwise being lit by the mouse
2697 if((Multi_ts_hotspot_type == MULTI_TS_SLOT_LIST) && (Multi_ts_hotspot_index == slot_index)){
2698 return ICON_FRAME_HOT;
2701 // normal unhighlighted frame
2702 return ICON_FRAME_NORMAL;
2705 // select the given slot and setup any information, etc
2706 void multi_ts_select_ship()
2710 int n_chars[MAX_BRIEF_LINES];
2711 char ship_desc[1000];
2712 char *p_str[MAX_BRIEF_LINES];
2716 // blast all current text
2717 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2718 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2720 // get the selected ship class
2721 Assert(Multi_ts_select_index >= 0);
2722 Multi_ts_select_ship_class = -1;
2723 switch(Multi_ts_select_type){
2724 case MULTI_TS_SLOT_LIST:
2725 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
2727 case MULTI_TS_AVAIL_LIST:
2728 Multi_ts_select_ship_class = multi_ts_get_avail_ship_class(Multi_ts_select_index);
2729 // if he has selected an empty slot, don't do anything
2730 if(Multi_ts_select_ship_class < 0){
2735 // should always have one of the 2 above types selected
2740 // split the text info up
2742 Assert(Multi_ts_select_ship_class >= 0);
2743 Assert((Ship_info[Multi_ts_select_ship_class].desc != NULL) && strlen(Ship_info[Multi_ts_select_ship_class].desc));
2745 // strip out newlines
2746 memset(ship_desc,0,1000);
2747 strcpy(ship_desc,Ship_info[Multi_ts_select_ship_class].desc);
2748 token = strtok(ship_desc,"\n");
2750 strcpy(Multi_ts_ship_info_text,token);
2751 while(token != NULL){
2752 token = strtok(NULL,"\n");
2754 strcat(Multi_ts_ship_info_text," ");
2755 strcat(Multi_ts_ship_info_text,token);
2760 if(strlen(Multi_ts_ship_info_text) > 0){
2761 // split the string into multiple lines
2762 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);
2764 // copy the split up lines into the text lines array
2765 for (idx=0;idx<n_lines;idx++ ) {
2766 Assert(n_chars[idx] < MULTI_TS_SHIP_INFO_MAX_LINE_LEN);
2767 strncpy(Multi_ts_ship_info_lines[idx], p_str[idx], n_chars[idx]);
2768 Multi_ts_ship_info_lines[idx][n_chars[idx]] = 0;
2769 drop_leading_white_space(Multi_ts_ship_info_lines[idx]);
2772 // get the line count
2773 Multi_ts_ship_info_line_count = n_lines;
2775 // set the line count to
2776 Multi_ts_ship_info_line_count = 0;
2781 // handle all details when the commit button is pressed (including possibly reporting errors/popups)
2782 void multi_ts_commit_pressed()
2784 // if my team's slots are still not "locked", we cannot commit unless we're the only player in the game
2785 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2786 if(multi_num_players() != 1){
2787 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("Players have not yet been assigned to their ships",751));
2790 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
2794 // check to see if its not ok for this player to commit
2795 switch(multi_ts_ok_to_commit()){
2796 // yes, it _is_ ok to commit
2798 extern void commit_pressed();
2802 // player has not assigned all necessary ships
2804 gamesnd_play_iface(SND_GENERAL_FAIL);
2805 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("You have not yet assigned all necessary ships",752));
2808 // there are ships without primary weapons
2810 gamesnd_play_iface(SND_GENERAL_FAIL);
2811 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without primary weapons!",753));
2814 // there are ships without secondary weapons
2816 gamesnd_play_iface(SND_GENERAL_FAIL);
2817 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without secondary weapons!",754));
2822 // is it ok for this player to commit
2823 int multi_ts_ok_to_commit()
2826 int primary_ok,secondary_ok;
2828 // if this player is an observer, he can always commit
2829 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2833 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2834 // if this is a player slot this player can modify and it is empty, then he cannot continue
2835 // implies there is never an object in this slot
2836 if((Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2837 // implies player can't touch this slot anyway
2838 !multi_ts_disabled_slot(idx) &&
2839 // implies that there should be a player ship here but there isn't
2840 ((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)) ){
2844 // 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
2845 if( (Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2846 ((Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER) ||
2847 (Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP)) &&
2848 !multi_ts_disabled_slot(idx)){
2852 // go through all weapons in the list
2853 for(s_idx=0;s_idx<MAX_WL_WEAPONS;s_idx++){
2854 // if this slot has a weapon with a greater than 0 count, check
2855 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)){
2856 switch(Weapon_info[Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx]].subtype){
2870 // if we've got both primary and secondary weapons
2871 if(primary_ok && secondary_ok){
2876 // if the ship doesn't have primary weapons
2881 // if the ship doesn't have secondary weapons
2891 // check to see that no illegal ship settings have occurred
2892 void multi_ts_check_errors()
2898 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2899 if(Multi_ts_team[0].multi_ts_objnum[idx] == -1){
2903 shipp = &Ships[Objects[Multi_ts_team[0].multi_ts_objnum[idx]].instance];
2904 Assert((shipp->weapons.current_primary_bank != -1) && (shipp->weapons.current_secondary_bank != -1));
2910 // ------------------------------------------------------------------------------------------------------
2911 // TEAM SELECT PACKET HANDLERS
2914 // send a player slot position update
2915 void send_pslot_update_packet(int team,int code,int sound)
2917 ubyte data[MAX_PACKET_SIZE],stop,val;
2920 int packet_size = 0;
2923 // build the header and add the data
2924 BUILD_HEADER(SLOT_UPDATE);
2934 // add the sound to play
2935 s_sound = (short)sound;
2938 // add data based upon the packet code
2940 case TS_CODE_LOCK_TEAM:
2941 // don't have to do anything
2943 case TS_CODE_PLAYER_UPDATE:
2944 // only the host should ever be doing this
2945 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
2947 // add individual slot data
2948 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
2949 if(Multi_ts_team[team].multi_ts_flag[idx] != MULTI_TS_FLAG_NONE){
2958 // add the ship class
2959 val = (ubyte)Wss_slots_teams[team][idx].ship_class;
2962 // add the objnum we're working with
2963 i_tmp = Multi_ts_team[team].multi_ts_objnum[idx];
2966 // add a byte indicating if a player is here or not
2967 if(Multi_ts_team[team].multi_ts_player[idx] == NULL){
2974 // if there's a player, add his address
2976 ADD_DATA(Multi_ts_team[team].multi_ts_player[idx]->player_id);
2978 // should also update his p_info settings locally
2979 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_class = Wss_slots_teams[team][idx].ship_class;
2980 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_index = idx;
2983 // 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)
2984 if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER){
2986 } else if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP){
2994 // add a final stop byte
3003 // send the packet to the standalone
3004 if(Net_player->flags & NETINFO_FLAG_AM_MASTER) {
3005 multi_io_send_to_all_reliable(data, packet_size);
3007 multi_io_send_reliable(Net_player, data, packet_size);
3011 // process a player slot position update
3012 void process_pslot_update_packet(ubyte *data, header *hinfo)
3014 int offset = HEADER_LENGTH;
3016 int player_index,idx,team,code,objnum;
3019 ubyte stop,val,slot_num,ship_class;
3021 my_index = Net_player->p_info.ship_index;
3023 // if we're the standalone, then we should be routing this data to all the other clients
3025 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3026 // fill in the address information of where this came from
3027 player_index = find_player_id(hinfo->id);
3028 Assert(player_index != -1);
3039 // get the sound to play
3042 // process the different opcodes
3044 case TS_CODE_LOCK_TEAM:
3046 Multi_ts_team[team].multi_players_locked = 1;
3048 // if this was my team, sync stuff up
3049 if((team == Net_player->p_info.team) && !(Game_mode & GM_STANDALONE_SERVER)){
3050 multi_ts_set_status_bar_mode(1);
3051 multi_ts_sync_interface();
3052 ss_recalc_multiplayer_slots();
3055 // if this is the standalone server, we need to re-route the packet here and there
3056 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3057 // in team vs team mode, only a team captain should ever be sending this
3058 if(Netgame.type_flags & NG_TYPE_TEAM){
3059 Assert(Net_players[player_index].flags & NETINFO_FLAG_TEAM_CAPTAIN);
3061 // in any other mode, it better be coming from the game host
3063 Assert(Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST);
3066 // re-route to all other players
3067 for(idx=0;idx<MAX_PLAYERS;idx++){
3068 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
3069 multi_io_send_reliable(&Net_players[idx], data, offset);
3074 case TS_CODE_PLAYER_UPDATE:
3075 // get the first stop byte
3077 while(stop != 0xff){
3081 // get the ship class
3082 GET_DATA(ship_class);
3087 // flag indicating if a player is in this slot
3090 // look the player up
3091 GET_DATA(player_id);
3092 player_index = find_player_id(player_id);
3094 // if we couldn't find him
3095 if(player_index == -1){
3096 nprintf(("Network","Couldn't find player for pslot update!\n"));
3097 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3099 // if we found him, assign him to this ship
3101 Net_players[player_index].p_info.ship_class = (int)ship_class;
3102 Net_players[player_index].p_info.ship_index = (int)slot_num;
3103 multi_assign_player_ship(player_index,&Objects[objnum],(int)ship_class);
3106 Multi_ts_team[team].multi_ts_player[slot_num] = &Net_players[player_index];
3108 // if this was me and my ship index changed, update the weapon select screen
3109 if(my_index != Net_player->p_info.ship_index){
3110 wl_reset_selected_slot();
3112 my_index = Net_player->p_info.ship_index;
3116 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3119 // get the ship flag byte
3121 Objects[objnum].flags &= ~(OF_PLAYER_SHIP | OF_COULD_BE_PLAYER);
3124 Objects[objnum].flags |= OF_PLAYER_SHIP;
3127 obj_set_flags( &Objects[objnum], Objects[objnum].flags | OF_COULD_BE_PLAYER );
3131 // get the next stop byte
3134 // if we have a sound we're supposed to play
3135 if((sound != -1) && !(Game_mode & GM_STANDALONE_SERVER) && (gameseq_get_state() == GS_STATE_TEAM_SELECT)){
3136 gamesnd_play_iface(sound);
3139 // if i'm the standalone server, I should rebroadcast this packet
3140 if(Game_mode & GM_STANDALONE_SERVER){
3141 for(idx=0;idx<MAX_PLAYERS;idx++){
3142 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_HOST(Net_players[idx]) && (Net_player != &Net_players[idx])){
3143 multi_io_send_reliable(&Net_players[idx], data, offset);
3151 // recalculate stuff
3152 if(!(Game_mode & GM_STANDALONE_SERVER)){
3153 ss_recalc_multiplayer_slots();