2 * $Logfile: /Freespace2/code/Network/MultiTeamSelect.cpp $
7 * Multiplayer Team Selection Code
10 * Revision 1.2 2002/05/07 03:16:47 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 27 9/13/99 12:54p Jefff
20 * 26 9/12/99 3:21p Jefff
21 * commit button coord fix in 640
23 * 25 8/05/99 9:57p Jefff
24 * fixed some button wierdness
26 * 24 8/05/99 5:08p Jefff
27 * fixed some location probs
29 * 23 7/28/99 5:34p Dave
30 * Nailed the missing stats bug to the wall. Problem was optimized build
31 * and using GET_DATA() with array elements. BLECH.
33 * 22 7/24/99 6:02p Jefff
34 * Added "lock" text to lock button
36 * 21 5/03/99 8:32p Dave
37 * New version of multi host options screen.
39 * 20 3/25/99 6:36p Neilk
40 * more hires coord fixes
42 * 19 3/25/99 2:44p Neilk
45 * 18 3/23/99 11:56a Neilk
46 * new source safe checkin
48 * 17 3/10/99 6:50p Dave
49 * Changed the way we buffer packets for all clients. Optimized turret
50 * fired packets. Did some weapon firing optimizations.
52 * 16 3/09/99 6:24p Dave
53 * More work on object update revamping. Identified several sources of
54 * unnecessary bandwidth.
56 * 15 2/21/99 6:02p Dave
57 * Fixed standalone WSS packets.
59 * 14 2/11/99 3:08p Dave
60 * PXO refresh button. Very preliminary squad war support.
62 * 13 2/01/99 5:55p Dave
63 * Removed the idea of explicit bitmaps for buttons. Fixed text
64 * highlighting for disabled gadgets.
66 * 12 1/30/99 5:08p Dave
67 * More new hi-res stuff.Support for nice D3D textures.
69 * 11 1/30/99 1:29a Dave
70 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
71 * screen. Fixed beam weapon death messages.
73 * 10 1/29/99 5:07p Dave
74 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
77 * 9 1/13/99 7:19p Neilk
78 * Converted Mission Brief, Barracks, Synch to high res support
80 * 8 12/18/98 1:13a Dave
81 * Rough 1024x768 support for Direct3D. Proper detection and usage through
84 * 7 11/30/98 1:07p Dave
85 * 16 bit conversion, first run.
87 * 6 11/19/98 8:04a Dave
88 * Full support for D3-style reliable sockets. Revamped packet lag/loss
89 * system, made it receiver side and at the lowest possible level.
91 * 5 11/17/98 11:12a Dave
92 * Removed player identification by address. Now assign explicit id #'s.
94 * 4 11/05/98 5:55p Dave
95 * Big pass at reducing #includes
97 * 3 10/13/98 9:29a Dave
98 * Started neatening up freespace.h. Many variables renamed and
99 * reorganized. Added AlphaColors.[h,cpp]
101 * 2 10/07/98 10:53a Dave
104 * 1 10/07/98 10:50a Dave
106 * 112 9/18/98 2:22a Dave
107 * Fixed freespace-side PXO api to correctly handle length 10 id strings.
108 * Fixed team select screen to handle alpha/beta/gamma ships which are not
109 * marked as OF_PLAYER_SHIP
111 * 111 9/17/98 3:08p Dave
112 * PXO to non-pxo game warning popup. Player icon stuff in create and join
113 * game screens. Upped server count refresh time in PXO to 35 secs (from
116 * 110 8/20/98 5:31p Dave
117 * Put in handy multiplayer logfile system. Now need to put in useful
118 * applications of it all over the code.
120 * 109 8/07/98 10:17a Allender
121 * use obj_set_flags for setting COULD_BE_PLAYER flag to trap bugs
123 * 108 7/24/98 9:27a Dave
124 * Tidied up endgame sequencing by removing several old flags and
125 * standardizing _all_ endgame stuff with a single function call.
127 * 107 6/13/98 6:01p Hoffoss
128 * Externalized all new (or forgot to be added) strings to all the code.
130 * 106 6/13/98 3:19p Hoffoss
131 * NOX()ed out a bunch of strings that shouldn't be translated.
133 * 105 5/19/98 8:35p Dave
134 * Revamp PXO channel listing system. Send campaign goals/events to
135 * clients for evaluation. Made lock button pressable on all screens.
137 * 104 5/19/98 11:23a Dave
138 * Change mask value for "lock" button.
140 * 103 5/18/98 12:41a Allender
141 * fixed subsystem problems on clients (i.e. not reporting properly on
142 * damage indicator). Fixed ingame join problem with respawns. minor
145 * 102 5/17/98 1:43a Dave
146 * Eradicated chatbox problems. Remove speed match for observers. Put in
147 * help screens for PXO. Fix messaging and end mission privelges. Fixed
148 * team select screen bugs. Misc UI fixes.
150 * 101 5/15/98 5:16p Dave
151 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
152 * status for team vs. team. Put in asserts to check for invalid team vs.
155 * 100 5/10/98 7:06p Dave
156 * Fix endgame sequencing ESC key. Changed how host options warning popups
157 * are done. Fixed pause/message scrollback/options screen problems in mp.
158 * Make sure observer HUD doesn't try to lock weapons.
162 #include "multiteamselect.h"
168 #include "linklist.h"
169 #include "gamesequence.h"
171 #include "multiutil.h"
172 #include "freespace.h"
173 #include "missionscreencommon.h"
174 #include "missionshipchoice.h"
175 #include "missionweaponchoice.h"
176 #include "missionbrief.h"
177 #include "missionparse.h"
178 #include "multimsgs.h"
179 #include "snazzyui.h"
183 #include "multi_endgame.h"
184 #include "alphacolors.h"
187 // ------------------------------------------------------------------------------------------------------
188 // TEAM SELECT DEFINES/VARS
191 // mission screen common data
192 extern int Next_screen;
197 #define MULTI_TS_PALETTE "InterfacePalette"
199 char *Multi_ts_bitmap_fname[GR_NUM_RESOLUTIONS] = {
200 "TeamSelect", // GR_640
201 "2_TeamSelect" // GR_1024
204 char *Multi_ts_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
205 "TeamSelect-M", // GR_640
206 "2_TeamSelect-M" // GR_1024
209 // constants for coordinate lookup
210 #define MULTI_TS_X_COORD 0
211 #define MULTI_TS_Y_COORD 1
212 #define MULTI_TS_W_COORD 2
213 #define MULTI_TS_H_COORD 3
215 #define MULTI_TS_NUM_BUTTONS 7
216 #define MULTI_TS_BRIEFING 0 // go to the briefing
217 #define MULTI_TS_SHIP_SELECT 1 // this screen
218 #define MULTI_TS_WEAPON_SELECT 2 // go to the weapon select screen
219 #define MULTI_TS_SHIPS_UP 3 // scroll the ships list up
220 #define MULTI_TS_SHIPS_DOWN 4 // scroll the ships list down
221 #define MULTI_TS_COMMIT 5 // commit
222 #define MULTI_TS_LOCK 6 // lock (free) ship/weapon select
224 ui_button_info Multi_ts_buttons[GR_NUM_RESOLUTIONS][MULTI_TS_NUM_BUTTONS] = {
226 ui_button_info("CB_00", 7, 3, 37, 7, 0),
227 ui_button_info("CB_01", 7, 19, 37, 23, 1),
228 ui_button_info("CB_02", 7, 35, 37, 39, 2),
229 ui_button_info("TSB_03", 5, 303, -1, -1, 3),
230 ui_button_info("TSB_04", 5, 454, -1, -1, 4),
231 ui_button_info("TSB_09", 571, 425, 572, 413, 9),
232 ui_button_info("TSB_34", 603, 374, 602, 364, 34)
236 ui_button_info("2_CB_00", 12, 5, 59, 12, 0),
237 ui_button_info("2_CB_01", 12, 31, 59, 37, 1),
238 ui_button_info("2_CB_02", 12, 56, 59, 62, 2),
239 ui_button_info("2_TSB_03", 8, 485, -1, -1, 3),
240 ui_button_info("2_TSB_04", 8, 727, -1, -1, 4),
241 ui_button_info("2_TSB_09", 914, 681, 937, 660, 9),
242 ui_button_info("2_TSB_34", 966, 599, 964, 584, 34)
247 // players locked ani graphic
248 #define MULTI_TS_NUM_LOCKED_BITMAPS 3
250 char *Multi_ts_bmap_names[GR_NUM_RESOLUTIONS][3] = {
262 int Multi_ts_locked_bitmaps[MULTI_TS_NUM_LOCKED_BITMAPS];
265 // snazzy menu regions
266 #define TSWING_0_SHIP_0 10
267 #define TSWING_0_SHIP_1 12
268 #define TSWING_0_SHIP_2 14
269 #define TSWING_0_SHIP_3 16
270 #define TSWING_1_SHIP_0 18
271 #define TSWING_1_SHIP_1 20
272 #define TSWING_1_SHIP_2 22
273 #define TSWING_1_SHIP_3 24
274 #define TSWING_2_SHIP_0 26
275 #define TSWING_2_SHIP_1 28
276 #define TSWING_2_SHIP_2 30
277 #define TSWING_2_SHIP_3 32
279 #define TSWING_0_NAME_0 11
280 #define TSWING_0_NAME_1 13
281 #define TSWING_0_NAME_2 15
282 #define TSWING_0_NAME_3 17
283 #define TSWING_1_NAME_0 19
284 #define TSWING_1_NAME_1 21
285 #define TSWING_1_NAME_2 23
286 #define TSWING_1_NAME_3 25
287 #define TSWING_2_NAME_0 27
288 #define TSWING_2_NAME_1 29
289 #define TSWING_2_NAME_2 31
290 #define TSWING_2_NAME_3 33
292 #define TSWING_LIST_0 5
293 #define TSWING_LIST_1 6
294 #define TSWING_LIST_2 7
295 #define TSWING_LIST_3 8
297 #define MULTI_TS_SLOT_LIST 0
298 #define MULTI_TS_PLAYER_LIST 1
299 #define MULTI_TS_AVAIL_LIST 2
302 #define MULTI_TS_NUM_SNAZZY_REGIONS 28
305 int Multi_ts_inited = 0;
306 int Multi_ts_snazzy_regions;
307 ubyte *Multi_ts_mask_data;
308 int Multi_ts_mask_w, Multi_ts_mask_h;
309 MENU_REGION Multi_ts_region[MULTI_TS_NUM_SNAZZY_REGIONS];
310 UI_WINDOW Multi_ts_window;
313 #define MULTI_TS_NUM_SHIP_SLOTS_TEAM 4 // # of ship slots in team v team
314 #define MULTI_TS_FLAG_NONE -2 // never has any ships
315 #define MULTI_TS_FLAG_EMPTY -1 // currently empty
316 char *Multi_ts_slot_names[MULTI_TS_NUM_SHIP_SLOTS] = { //
317 "alpha 1", "alpha 2", "alpha 3", "alpha 4",
318 "beta 1", "beta 2", "beta 3", "beta 4",
319 "gamma 1", "gamma 2", "gamma 3", "gamma 4"
321 char *Multi_ts_slot_team_names[MULTI_TS_MAX_TEAMS][MULTI_TS_NUM_SHIP_SLOTS_TEAM] = {
322 {"alpha 1", "alpha 2", "alpha 3", "alpha 4"},
323 {"zeta 1", "zeta 2", "zeta 3", "zeta 4"}
326 static int Multi_ts_slot_icon_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][2] = { // x,y
377 static int Multi_ts_slot_text_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][3] = { // x,y,width
379 {112,330,181-112}, // GR_640
380 {187,517,181-112} // GR_1024
383 {74,377,143-74}, // GR_640
384 {126,592,143-74} // GR_1024
387 {149,377,218-149},// GR_640
388 {248,592,218-149} // GR_1024
391 {112,424,181-112},// GR_640
392 {187,667,181-112} // GR_1024
395 {274,330,343-274},// GR_640
396 {446,517,343-274} // GR_1024
399 {236,377,305-236},// GR_640
400 {385,592,305-236} // GR_1024
403 {311,377,380-311},// GR_640
404 {507,592,380-311} // GR_1024
407 {274,424,343-274},// GR_640
408 {446,667,343-274} // GR_1024
411 {437,330,506-437},// GR_640
412 {707,517,506-437} // GR_1024
415 {399,377,468-399},// GR_640
416 {646,592,468-399} // GR_1024
419 {474,377,543-474},// GR_640
420 {768,592,543-474} // GR_1024
423 {437,424,506-437},// GR_640
424 {707,667,506-437} // GR_1024
428 // avail ship list data
429 #define MULTI_TS_AVAIL_MAX_DISPLAY 4
430 static int Multi_ts_avail_coords[MULTI_TS_AVAIL_MAX_DISPLAY][GR_NUM_RESOLUTIONS][2] = { // x,y coords
448 int Multi_ts_avail_start = 0; // starting index of where we will display the available ships
449 int Multi_ts_avail_count = 0; // the # of available ship classes
451 // ship information stuff
452 #define MULTI_TS_SHIP_INFO_MAX_LINE_LEN 150
453 #define MULTI_TS_SHIP_INFO_MAX_LINES 10
454 #define MULTI_TS_SHIP_INFO_MAX_TEXT (MULTI_TS_SHIP_INFO_MAX_LINE_LEN * MULTI_TS_SHIP_INFO_MAX_LINES)
456 static int Multi_ts_ship_info_coords[GR_NUM_RESOLUTIONS][3] = {
465 char Multi_ts_ship_info_lines[MULTI_TS_SHIP_INFO_MAX_LINES][MULTI_TS_SHIP_INFO_MAX_LINE_LEN];
466 char Multi_ts_ship_info_text[MULTI_TS_SHIP_INFO_MAX_TEXT];
467 int Multi_ts_ship_info_line_count;
470 static int Multi_ts_status_coords[GR_NUM_RESOLUTIONS][3] = {
479 int Multi_ts_status_bar_mode = 0;
481 // carried icon information
482 int Multi_ts_carried_flag = 0;
483 int Multi_ts_clicked_flag = 0;
484 int Multi_ts_clicked_x,Multi_ts_clicked_y;
485 int Multi_ts_carried_ship_class;
486 int Multi_ts_carried_from_type = 0;
487 int Multi_ts_carried_from_index = 0;
489 // selected ship types (for informational purposes)
490 int Multi_ts_select_type = -1;
491 int Multi_ts_select_index = -1;
492 int Multi_ts_select_ship_class = -1;
494 // per-frame mouse hotspot vars
495 int Multi_ts_hotspot_type = -1;
496 int Multi_ts_hotspot_index = -1;
499 #define TS_GRAB_FROM_LIST 0
500 #define TS_SWAP_LIST_SLOT 1
501 #define TS_SWAP_SLOT_SLOT 2
502 #define TS_DUMP_TO_LIST 3
503 #define TS_SWAP_PLAYER_PLAYER 4
504 #define TS_MOVE_PLAYER 5
507 #define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
508 #define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team
511 #define MULTI_TS_FLAG_NONE -2 // slot is _always_ empty
512 #define MULTI_TS_FLAG_EMPTY -1 // flag is temporarily empty
513 typedef struct ts_team_data {
514 int multi_ts_objnum[MULTI_TS_NUM_SHIP_SLOTS]; // objnums for all slots in this team
515 net_player *multi_ts_player[MULTI_TS_NUM_SHIP_SLOTS]; // net players corresponding to the same slots
516 int multi_ts_flag[MULTI_TS_NUM_SHIP_SLOTS]; // flags indicating the "status" of a slot
517 int multi_players_locked; // are the players locked into place
519 ts_team_data Multi_ts_team[MULTI_TS_MAX_TEAMS]; // data for all teams
521 // deleted ship objnums
522 int Multi_ts_deleted_objnums[MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
523 int Multi_ts_num_deleted;
527 // ------------------------------------------------------------------------------------------------------
528 // TEAM SELECT FORWARD DECLARATIONS
531 // check for button presses
532 void multi_ts_check_buttons();
534 // act on a button press
535 void multi_ts_button_pressed(int n);
537 // initialize all screen data, etc
538 void multi_ts_init_graphics();
540 // blit all of the icons representing all wings
541 void multi_ts_blit_wings();
543 // blit all of the player callsigns under the correct ships
544 void multi_ts_blit_wing_callsigns();
546 // blit the ships on the avail list
547 void multi_ts_blit_avail_ships();
549 // initialize the snazzy menu stuff for dragging ships,players around
550 void multi_ts_init_snazzy();
552 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
553 int multi_ts_region_type(int region);
555 // convert the region num to a ship slot index
556 int multi_ts_slot_index(int region);
558 // convert the region num to an avail list index
559 int multi_ts_avail_index(int region);
561 // convert the region num to a player slot index
562 int multi_ts_player_index(int region);
564 // blit the status bar
565 void multi_ts_blit_status_bar();
567 // assign the correct players to the correct slots
568 void multi_ts_init_players();
570 // assign the correct objnums to the correct slots
571 void multi_ts_init_objnums();
573 // assign the correct flags to the correct slots
574 void multi_ts_init_flags();
576 // get the proper team and slot index for the given ship name
577 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index);
579 // handle an available ship scroll down button press
580 void multi_ts_avail_scroll_down();
582 // handle an available ship scroll up button press
583 void multi_ts_avail_scroll_up();
585 // handle all mouse events (clicking, dragging, and dropping)
586 void multi_ts_handle_mouse();
588 // can the specified player perform the action he is attempting
589 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index = -1);
591 // determine the kind of drag and drop operation this is
592 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index = -1);
594 // swap two player positions
595 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index = -1);
598 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index = -1);
600 // get the ship class of the current index in the avail list or -1 if none exists
601 int multi_ts_get_avail_ship_class(int index);
603 // blit the currently carried icon (if any)
604 void multi_ts_blit_carried_icon();
606 // if the (console) player is allowed to grab a player slot at this point
607 int multi_ts_can_grab_player(int slot_index,int player_index = -1);
609 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
610 int multi_ts_slot_bmap_num(int slot_index);
612 // blit any active ship information text
613 void multi_ts_blit_ship_info();
615 // select the given slot and setup any information, etc
616 void multi_ts_select_ship();
618 // is it ok for this player to commit
619 int multi_ts_ok_to_commit();
621 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
622 int multi_ts_avail_bmap_num(int slot_index);
624 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
625 void multi_ts_set_status_bar_mode(int m);
627 // check to see that no illegal ship settings have occurred
628 void multi_ts_check_errors();
630 // ------------------------------------------------------------------------------------------------------
631 // TEAM SELECT FUNCTIONS
634 // initialize the team select screen (always call, even when switching between weapon select, etc)
637 // if we haven't initialized at all yet, then do it
638 if(!Multi_ts_inited){
639 multi_ts_init_graphics();
643 // use the common interface palette
644 multi_common_set_palette();
646 // set the interface palette
647 // common_set_interface_palette(MULTI_TS_PALETTE);
649 Net_player->state = NETPLAYER_STATE_SHIP_SELECT;
651 Current_screen = ON_SHIP_SELECT;
654 // initialize all critical internal data structures
655 void multi_ts_common_init()
659 // reset timestamps here. they seem to get hosed by the loadinh of the mission file
660 multi_reset_timestamps();
662 // saying "not allowed to mess with ships"
663 Multi_ts_status_bar_mode = 0;
665 // intialize ship info stuff
666 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
667 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
668 Multi_ts_ship_info_line_count = 0;
670 // initialize carried icon information
671 Multi_ts_carried_flag = 0;
672 Multi_ts_clicked_flag = 0;
673 Multi_ts_clicked_x = 0;
674 Multi_ts_clicked_y = 0;
675 Multi_ts_carried_ship_class = -1;
676 Multi_ts_carried_from_type = 0;
677 Multi_ts_carried_from_index = 0;
679 // selected slot information (should be default player ship)
680 if(!MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
681 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
682 Multi_ts_select_index = Net_player->p_info.ship_index;
684 // select this ship and setup his info
685 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
686 multi_ts_select_ship();
688 Multi_ts_select_type = -1;
689 Multi_ts_select_index = -1;
691 // no ship class selected for information purposes
692 Multi_ts_select_ship_class = -1;
695 // deleted ship information
696 memset(Multi_ts_deleted_objnums,0,sizeof(int) * MULTI_TS_MAX_TEAMS * MULTI_TS_NUM_SHIP_SLOTS);
697 Multi_ts_num_deleted = 0;
699 // mouse hotspot information
700 Multi_ts_hotspot_type = -1;
701 Multi_ts_hotspot_index = -1;
703 // initialize avail ship list data
704 Multi_ts_avail_start = 0;
706 // load the locked button bitmaps bitmaps
707 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
708 Multi_ts_locked_bitmaps[idx] = -1;
709 Multi_ts_locked_bitmaps[idx] = bm_load(Multi_ts_bmap_names[gr_screen.res][idx]);
712 // blast the team data clean
713 memset(Multi_ts_team,0,sizeof(ts_team_data) * MULTI_TS_MAX_TEAMS);
715 // assign the correct players to the correct slots
716 multi_ts_init_players();
718 // assign the correct objnums to the correct slots
719 multi_ts_init_objnums();
721 // sync the interface as normal
722 multi_ts_sync_interface();
725 // do frame for team select
728 int k = chatbox_process();
729 k = Multi_ts_window.process(k);
731 // process any keypresses
734 gamesnd_play_iface(SND_USER_SELECT);
735 multi_quit_game(PROMPT_ALL);
738 // cycle to the weapon select screen
740 gamesnd_play_iface(SND_USER_SELECT);
741 Next_screen = ON_WEAPON_SELECT;
742 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
745 case KEY_ENTER|KEY_CTRLED:
746 multi_ts_commit_pressed();
750 // check any button presses
751 multi_ts_check_buttons();
753 // handle all mouse related events
754 multi_ts_handle_mouse();
757 multi_ts_check_errors();
759 // draw the background, etc
761 GR_MAYBE_CLEAR_RES(Multi_ts_bitmap);
762 if(Multi_ts_bitmap != -1){
763 gr_set_bitmap(Multi_ts_bitmap);
766 Multi_ts_window.draw();
769 multi_ts_blit_wings();
771 // blit all callsigns
772 multi_ts_blit_wing_callsigns();
774 // blit the ships on the available list
775 multi_ts_blit_avail_ships();
777 // force draw the ship select button
778 Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button.draw_forced(2);
780 // force draw the "locked" button if necessary
781 if(multi_ts_is_locked()){
782 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(2);
784 if( ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) ||
785 ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST)) ){
786 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(0);
788 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw();
792 // blit any active ship information
793 multi_ts_blit_ship_info();
795 // blit the status bar
796 multi_ts_blit_status_bar();
798 // render the chatbox
802 Multi_ts_window.draw_tooltip();
804 // display the status of the voice system
805 multi_common_voice_display_status();
807 // blit any carried icons
808 multi_ts_blit_carried_icon();
814 // close the team select screen (always call, even when switching between weapon select, etc)
815 void multi_ts_close()
819 if(!Multi_ts_inited){
825 // shut down the snazzy menu
828 // unload any bitmaps
829 if(!bm_unload(Multi_ts_bitmap)){
830 nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ts_bitmap_fname[gr_screen.res]));
832 for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
833 if(Multi_ts_locked_bitmaps[idx] != -1){
834 bm_release(Multi_ts_locked_bitmaps[idx]);
835 Multi_ts_locked_bitmaps[idx] = -1;
839 // destroy the UI_WINDOW
840 Multi_ts_window.destroy();
843 // is the given slot disabled for the specified player
844 int multi_ts_disabled_slot(int slot_num, int player_index)
848 // get the appropriate net player
849 if(player_index == -1){
852 pl = &Net_players[player_index];
855 // if the player is an observer, its _always_ disabled
856 if(pl->flags & NETINFO_FLAG_OBSERVER){
860 // if the flag for this team isn't set to "free" we can't do anything
861 if(!Multi_ts_team[pl->p_info.team].multi_players_locked){
865 // if the "leaders" only flag is set
866 if(Netgame.options.flags & MSO_FLAG_SS_LEADERS){
867 // in a team vs. team situation
868 if(Netgame.type_flags & NG_TYPE_TEAM){
869 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
873 // in a non team vs. team situation
875 if(pl->flags & NETINFO_FLAG_GAME_HOST){
880 // in a team vs. team situation
881 if(Netgame.type_flags & NG_TYPE_TEAM){
882 // if i'm the team captain I can mess with my own ships as well as those of the ai ships on my team
883 if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
884 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)){
891 // in a non team vs. team situation
893 // if we're the host, we can our own ship and ai ships
894 if(pl->flags & NETINFO_FLAG_GAME_HOST){
895 // can't grab player ships
896 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)){
904 // if this is our slot, then we can grab it
905 if(slot_num == pl->p_info.ship_index){
913 // is the given slot disabled for the specified player, _and_ it is his ship as well
914 int multi_ts_disabled_high_slot(int slot_index,int player_index)
918 // get the appropriate net player
919 if(player_index == -1){
922 pl = &Net_players[player_index];
925 // if this is disabled for him and its also _his_ slot
926 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)){
933 // resynch all display/interface elements based upon all the ship/weapon pool values
934 void multi_ts_sync_interface()
938 // item 1 - determine how many ship types are available in the ship pool
939 Multi_ts_avail_count = 0;
940 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
941 if(Ss_pool[idx] > 0){
942 Multi_ts_avail_count++;
946 // item 2 - make sure our local Multi_ts_slot_flag array is up to date
947 multi_ts_init_flags();
949 // item 3 - set/unset any necessary flags in underlying ship select data structures
950 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
951 switch(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx]){
952 case MULTI_TS_FLAG_EMPTY :
953 ss_make_slot_empty(idx);
955 case MULTI_TS_FLAG_NONE :
958 ss_make_slot_full(idx);
963 // item 4 - reset the locked/unlocked status of all ships in the weapon select screen
964 ss_recalc_multiplayer_slots();
967 void multi_ts_assign_players_all()
969 int idx,team_index,slot_index,found,player_count,shipnum;
970 char name_lookup[100];
973 // set all player ship indices to -1
974 for(idx=0;idx<MAX_PLAYERS;idx++){
975 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
976 Net_players[idx].p_info.ship_index = -1;
980 // merge the created object list with the actual object list so we have all available ships
981 obj_merge_created_list();
983 // get the # of players currently in the game
984 player_count = multi_num_players();
986 // always assign the host to Alpha 1 (or Zeta 1 in team vs. team - as appropriate)
987 memset(name_lookup,0,100);
988 if(Netgame.type_flags & NG_TYPE_TEAM){
989 switch(Netgame.host->p_info.team){
991 strcpy(name_lookup,NOX("alpha 1"));
994 strcpy(name_lookup,NOX("zeta 1"));
998 strcpy(name_lookup,NOX("alpha 1"));
1000 shipnum = ship_name_lookup(name_lookup);
1002 // if we couldn't find the ship for the host
1004 // Netgame.flags |= NG_FLAG_QUITTING;
1005 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1009 multi_ts_get_team_and_slot(Ships[shipnum].ship_name,&team_index,&slot_index);
1010 multi_assign_player_ship(NET_PLAYER_INDEX(Netgame.host),&Objects[Ships[shipnum].objnum],Ships[shipnum].ship_info_index);
1011 Netgame.host->p_info.ship_index = slot_index;
1012 Assert(Netgame.host->p_info.ship_index >= 0);
1013 Netgame.host->p_info.ship_class = Ships[shipnum].ship_info_index;
1014 Netgame.host->player->objnum = Ships[shipnum].objnum;
1016 // for each netplayer, try and find a ship
1017 objp = GET_FIRST(&obj_used_list);
1018 while(objp != END_OF_LIST(&obj_used_list)){
1019 // find a valid player ship - ignoring the ship which was assigned to the host
1020 if((objp->flags & OF_PLAYER_SHIP) && stricmp(Ships[objp->instance].ship_name,name_lookup)){
1021 // determine what team and slot this ship is
1022 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1023 Assert((team_index != -1) && (slot_index != -1));
1025 // in a team vs. team situation
1026 if(Netgame.type_flags & NG_TYPE_TEAM){
1027 // find a player on this team who needs a ship
1029 for(idx=0;idx<MAX_PLAYERS;idx++){
1030 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)){
1036 // in a non team vs. team situation
1038 // find any player on this who needs a ship
1040 for(idx=0;idx<MAX_PLAYERS;idx++){
1041 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1)){
1048 // if we found a player
1050 multi_assign_player_ship(idx,objp,Ships[objp->instance].ship_info_index);
1051 Net_players[idx].p_info.ship_index = slot_index;
1052 Assert(Net_players[idx].p_info.ship_index >= 0);
1053 Net_players[idx].p_info.ship_class = Ships[objp->instance].ship_info_index;
1054 Net_players[idx].player->objnum = OBJ_INDEX(objp);
1056 // decrement the player count
1059 objp->flags &= ~OF_PLAYER_SHIP;
1060 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1063 // if we've assigned all players, we're done
1064 if(player_count <= 0){
1069 // move to the next item
1070 objp = GET_NEXT(objp);
1073 // go through and change any ships marked as player ships to be COULD_BE_PLAYER
1074 if ( objp != END_OF_LIST(&obj_used_list) ) {
1075 for ( objp = GET_NEXT(objp); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1076 if ( objp->flags & OF_PLAYER_SHIP ){
1077 objp->flags &= ~OF_PLAYER_SHIP;
1078 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1083 if(Game_mode & GM_STANDALONE_SERVER){
1085 Net_player->player->objnum = -1;
1088 // check to make sure all players were assigned correctly
1089 for(idx=0;idx<MAX_PLAYERS;idx++){
1090 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
1091 // if this guy never got assigned a player ship, there's a mission problem
1092 if(Net_players[idx].p_info.ship_index == -1){
1093 // Netgame.flags |= NG_FLAG_QUITTING;
1094 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
1101 // delete ships which have been removed from the game, tidy things
1102 void multi_ts_create_wings()
1106 // the standalone never went through this screen so he should never call this function!
1107 // the standalone and all other clients will have this equivalent function performed whey they receieve
1108 // the post_sync_data_packet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1109 Assert(!(Game_mode & GM_STANDALONE_SERVER));
1111 // check status of all ships and delete or change ship type as necessary
1112 Multi_ts_num_deleted = 0;
1113 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1114 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1115 // otherwise if there's a valid ship in this spot
1116 if(Multi_ts_team[idx].multi_ts_flag[s_idx] >= 0){
1119 // set the ship type appropriately
1120 Assert(Wss_slots_teams[idx][s_idx].ship_class >= 0);
1122 objnum = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1123 change_ship_type(Objects[objnum].instance,Wss_slots_teams[idx][s_idx].ship_class);
1125 // set the ship weapons correctly
1126 wl_update_ship_weapons(objnum,&Wss_slots_teams[idx][s_idx]);
1128 // assign ts_index of the ship to point to the proper Wss_slots slot
1129 Ships[Objects[objnum].instance].ts_index = s_idx;
1130 } else if(Multi_ts_team[idx].multi_ts_flag[s_idx] == MULTI_TS_FLAG_EMPTY){
1131 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] >= 0);
1133 // mark the object as having been deleted
1134 Multi_ts_deleted_objnums[Multi_ts_num_deleted] = Multi_ts_team[idx].multi_ts_objnum[s_idx];
1137 ship_add_exited_ship( &Ships[Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance], SEF_PLAYER_DELETED );
1138 obj_delete(Multi_ts_deleted_objnums[Multi_ts_num_deleted]);
1139 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]);
1141 // increment the # of ships deleted
1142 Multi_ts_num_deleted++;
1148 // do any necessary processing for players who have left the game
1149 void multi_ts_handle_player_drop()
1154 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1155 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1156 // if we found him, clear his player slot and set his object back to being OF_COULD_BE_PLAYER
1157 if((Multi_ts_team[idx].multi_ts_player[s_idx] != NULL) && !MULTI_CONNECTED((*Multi_ts_team[idx].multi_ts_player[s_idx]))){
1158 Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1);
1159 Multi_ts_team[idx].multi_ts_player[s_idx] = NULL;
1160 Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags &= ~(OF_PLAYER_SHIP);
1161 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);
1167 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
1168 void multi_ts_set_status_bar_mode(int m)
1170 Multi_ts_status_bar_mode = m;
1173 // blit the proper "locked" button - used for weapon select and briefing screens
1174 void multi_ts_blit_locked_button()
1176 // if we're locked down and we have a valid bitmap
1177 if((Multi_ts_team[Net_player->p_info.team].multi_players_locked) && (Multi_ts_locked_bitmaps[2] != -1)){
1178 gr_set_bitmap(Multi_ts_locked_bitmaps[2]);
1179 gr_bitmap(Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1181 // draw as "not locked" if possible
1182 else if(Multi_ts_locked_bitmaps[0] != -1){
1183 gr_set_bitmap(Multi_ts_locked_bitmaps[0]);
1184 gr_bitmap( Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].x, Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].y);
1188 // the "lock" button has been pressed
1189 void multi_ts_lock_pressed()
1191 // do nothing if the button has already been pressed
1192 if(multi_ts_is_locked()){
1193 gamesnd_play_iface(SND_GENERAL_FAIL);
1197 if(Netgame.type_flags & NG_TYPE_TEAM){
1198 Assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
1200 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1202 gamesnd_play_iface(SND_USER_SELECT);
1204 // send a final player slot update packet
1205 send_pslot_update_packet(Net_player->p_info.team,TS_CODE_LOCK_TEAM,-1);
1206 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
1208 // sync interface stuff
1209 multi_ts_set_status_bar_mode(1);
1210 multi_ts_sync_interface();
1211 ss_recalc_multiplayer_slots();
1213 // disable this button now
1214 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1218 int multi_ts_is_locked()
1220 return Multi_ts_team[Net_player->p_info.team].multi_players_locked;
1223 // show a popup saying "only host and team captains can modify, etc, etc"
1224 void multi_ts_maybe_host_only_popup()
1227 // if this is because the "host modifies" option is set
1228 if((Netgame.options.flags & MSO_FLAG_SS_LEADERS) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1229 multi_ts_host_only_popup();
1232 if(Netgame.type == NG_TYPE_TEAM){
1233 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only team captains may modify ships and weapons in this game");
1235 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only the host may modify ships and weapons in this game");
1241 // ------------------------------------------------------------------------------------------------------
1242 // TEAM SELECT FORWARD DEFINITIONS
1245 // check for button presses
1246 void multi_ts_check_buttons()
1249 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1250 // we only really need to check for one button pressed at a time, so we can break after
1252 if(Multi_ts_buttons[gr_screen.res][idx].button.pressed()){
1253 multi_ts_button_pressed(idx);
1259 // act on a button press
1260 void multi_ts_button_pressed(int n)
1263 // back to the briefing screen
1264 case MULTI_TS_BRIEFING :
1265 gamesnd_play_iface(SND_USER_SELECT);
1266 Next_screen = ON_BRIEFING_SELECT;
1267 gameseq_post_event( GS_EVENT_START_BRIEFING );
1269 // already on this screen
1270 case MULTI_TS_SHIP_SELECT:
1271 gamesnd_play_iface(SND_GENERAL_FAIL);
1273 // back to the weapon select screen
1274 case MULTI_TS_WEAPON_SELECT:
1275 gamesnd_play_iface(SND_USER_SELECT);
1276 Next_screen = ON_WEAPON_SELECT;
1277 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
1279 // scroll the available ships list down
1280 case MULTI_TS_SHIPS_DOWN:
1281 multi_ts_avail_scroll_down();
1283 // scroll the available ships list up
1284 case MULTI_TS_SHIPS_UP:
1285 multi_ts_avail_scroll_up();
1287 // free ship/weapon select
1289 Assert(Game_mode & GM_MULTIPLAYER);
1290 // the "lock" button has been pressed
1291 multi_ts_lock_pressed();
1293 // disable the button if it is now locked
1294 if(multi_ts_is_locked()){
1295 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1299 case MULTI_TS_COMMIT :
1300 multi_ts_commit_pressed();
1303 gamesnd_play_iface(SND_GENERAL_FAIL);
1308 // initialize all screen data, etc
1309 void multi_ts_init_graphics()
1313 // create the interface window
1314 Multi_ts_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
1315 Multi_ts_window.set_mask_bmap(Multi_ts_bitmap_mask_fname[gr_screen.res]);
1317 // load the background bitmap
1318 Multi_ts_bitmap = bm_load(Multi_ts_bitmap_fname[gr_screen.res]);
1319 if(Multi_ts_bitmap < 0){
1320 // we failed to load the bitmap - this is very bad
1324 // create the interface buttons
1325 for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1326 // create the object
1327 if((idx == MULTI_TS_SHIPS_UP) || (idx == MULTI_TS_SHIPS_DOWN)){
1328 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);
1330 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);
1333 // set the sound to play when highlighted
1334 Multi_ts_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1336 // set the ani for the button
1337 Multi_ts_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ts_buttons[gr_screen.res][idx].filename);
1340 Multi_ts_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ts_buttons[gr_screen.res][idx].hotspot);
1344 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);
1345 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);
1346 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);
1347 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);
1348 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);
1350 // 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);
1351 // 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);
1355 // make the ship scrolling lists
1357 // if we're not the host of the game (or a tema captain in team vs. team mode), disable the lock button
1358 if (Netgame.type_flags & NG_TYPE_TEAM) {
1359 if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1360 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1363 if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1364 Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1368 // initialize the snazzy menu stuff (for grabbing ships, names, etc)
1369 multi_ts_init_snazzy();
1371 // create the chatbox (again, should not be necessary at this point)
1374 // sync the interface as normal
1375 multi_ts_sync_interface();
1378 // blit all of the icons representing all wings
1379 void multi_ts_blit_wings()
1383 // blit them all blindly for now
1384 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1385 // if this ship doesn't exist, then continue
1386 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1390 // otherwise blit the ship icon or the "empty" icon
1391 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY){
1392 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);
1394 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));
1396 // if this is a team vs team game, and the slot is occupised by a team captain, put a c there
1397 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)){
1398 gr_set_color_fast(&Color_bright);
1399 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 ]]
1405 // blit all of the player callsigns under the correct ships
1406 void multi_ts_blit_wing_callsigns()
1409 char callsign[CALLSIGN_LEN+2];
1412 // blit them all blindly for now
1413 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1414 // if this ship doesn't exist, then continue
1415 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1419 // if there is a player in the slot
1420 if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
1421 // make sure the string fits
1422 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->player->callsign);
1424 // determine if this is a locked AI ship
1425 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
1426 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
1427 strcpy(callsign, NOX("<"));
1428 strcat(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1429 strcat(callsign, NOX(">"));
1431 strcpy(callsign,XSTR("AI",738)); // [[ Artificial Intellegence ]]
1435 gr_force_fit_string(callsign, CALLSIGN_LEN, Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD]);
1437 // get the final length
1438 gr_get_string_size(&callsign_w, NULL, callsign);
1441 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)){
1442 gr_set_color_fast(&Color_text_active_hi);
1444 gr_set_color_fast(&Color_normal);
1446 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);
1450 // blit the ships on the avail list
1451 void multi_ts_blit_avail_ships()
1453 int display_count,ship_count,idx;
1456 // blit the availability of all ship counts
1459 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
1460 if(Ss_pool[idx] > 0){
1461 // if our starting display index is after this, then skip it
1462 if(ship_count < Multi_ts_avail_start){
1466 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));
1468 // blit the ship count available
1469 sprintf(count,"%d",Ss_pool[idx]);
1470 gr_set_color_fast(&Color_normal);
1471 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);
1473 // increment the counts
1479 // if we've reached the max amount we can display, then stop
1480 if(display_count >= MULTI_TS_AVAIL_MAX_DISPLAY){
1486 // initialize the snazzy menu stuff for dragging ships,players around
1487 void multi_ts_init_snazzy()
1489 // initialize the snazzy menu
1493 Multi_ts_snazzy_regions = 0;
1494 memset(Multi_ts_region,0,sizeof(MENU_REGION) * MULTI_TS_NUM_SNAZZY_REGIONS);
1496 // get a pointer to the mask bitmap data
1497 Multi_ts_mask_data = (ubyte*)Multi_ts_window.get_mask_data(&Multi_ts_mask_w, &Multi_ts_mask_h);
1499 // add the wing slots information
1500 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_0, 0);
1501 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_1, 0);
1502 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_2, 0);
1503 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_SHIP_3, 0);
1504 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_0, 0);
1505 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_1, 0);
1506 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_2, 0);
1507 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_SHIP_3, 0);
1508 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_0, 0);
1509 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_1, 0);
1510 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_2, 0);
1511 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_SHIP_3, 0);
1513 // add the name slots information
1514 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_0, 0);
1515 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_1, 0);
1516 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_2, 0);
1517 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_0_NAME_3, 0);
1518 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_0, 0);
1519 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_1, 0);
1520 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_2, 0);
1521 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_1_NAME_3, 0);
1522 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_0, 0);
1523 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_1, 0);
1524 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_2, 0);
1525 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_2_NAME_3, 0);
1527 // add the available ships region
1528 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_0, 0);
1529 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_1, 0);
1530 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_2, 0);
1531 snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "", TSWING_LIST_3, 0);
1534 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
1535 int multi_ts_region_type(int region)
1537 if((region == TSWING_0_SHIP_0) || (region == TSWING_0_SHIP_1) || (region == TSWING_0_SHIP_2) || (region == TSWING_0_SHIP_3) ||
1538 (region == TSWING_1_SHIP_0) || (region == TSWING_1_SHIP_1) || (region == TSWING_1_SHIP_2) || (region == TSWING_1_SHIP_3) ||
1539 (region == TSWING_2_SHIP_0) || (region == TSWING_2_SHIP_1) || (region == TSWING_2_SHIP_2) || (region == TSWING_2_SHIP_3) ){
1540 return MULTI_TS_SLOT_LIST;
1543 if((region == TSWING_0_NAME_0) || (region == TSWING_0_NAME_1) || (region == TSWING_0_NAME_2) || (region == TSWING_0_NAME_3) ||
1544 (region == TSWING_1_NAME_0) || (region == TSWING_1_NAME_1) || (region == TSWING_1_NAME_2) || (region == TSWING_1_NAME_3) ||
1545 (region == TSWING_2_NAME_0) || (region == TSWING_2_NAME_1) || (region == TSWING_2_NAME_2) || (region == TSWING_2_NAME_3) ){
1546 return MULTI_TS_PLAYER_LIST;
1549 if((region == TSWING_LIST_0) || (region == TSWING_LIST_1) || (region == TSWING_LIST_2) || (region == TSWING_LIST_3)){
1550 return MULTI_TS_AVAIL_LIST;
1556 // convert the region num to a ship slot index
1557 int multi_ts_slot_index(int region)
1560 case TSWING_0_SHIP_0:
1562 case TSWING_0_SHIP_1:
1564 case TSWING_0_SHIP_2:
1566 case TSWING_0_SHIP_3:
1568 case TSWING_1_SHIP_0:
1570 case TSWING_1_SHIP_1:
1572 case TSWING_1_SHIP_2:
1574 case TSWING_1_SHIP_3:
1576 case TSWING_2_SHIP_0:
1578 case TSWING_2_SHIP_1:
1580 case TSWING_2_SHIP_2:
1582 case TSWING_2_SHIP_3:
1589 // convert the region num to an avail list index (starting from absolute 0)
1590 int multi_ts_avail_index(int region)
1606 // convert the region num to a player slot index
1607 int multi_ts_player_index(int region)
1610 case TSWING_0_NAME_0:
1612 case TSWING_0_NAME_1:
1614 case TSWING_0_NAME_2:
1616 case TSWING_0_NAME_3:
1618 case TSWING_1_NAME_0:
1620 case TSWING_1_NAME_1:
1622 case TSWING_1_NAME_2:
1624 case TSWING_1_NAME_3:
1626 case TSWING_2_NAME_0:
1628 case TSWING_2_NAME_1:
1630 case TSWING_2_NAME_2:
1632 case TSWING_2_NAME_3:
1639 // blit any active ship information text
1640 void multi_ts_blit_ship_info()
1646 // if we don't have a valid ship selected, do nothing
1647 if(Multi_ts_select_ship_class == -1){
1651 // get the ship class
1652 sip = &Ship_info[Multi_ts_select_ship_class];
1655 y_start = Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_Y_COORD];
1659 // blit the ship class (name)
1660 gr_set_color_fast(&Color_normal);
1661 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Class",739));
1662 if(strlen(sip->name)){
1663 gr_set_color_fast(&Color_bright);
1664 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->name);
1668 // blit the ship type
1669 gr_set_color_fast(&Color_normal);
1670 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Type",740));
1671 if((sip->type_str != NULL) && strlen(sip->type_str)){
1672 gr_set_color_fast(&Color_bright);
1673 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->type_str);
1677 // blit the ship length
1678 gr_set_color_fast(&Color_normal);
1679 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Length",741));
1680 if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1681 gr_set_color_fast(&Color_bright);
1682 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->ship_length);
1686 // blit the max velocity
1687 gr_set_color_fast(&Color_normal);
1688 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Max Velocity",742));
1689 sprintf(str,XSTR("%d m/s",743),(int)sip->max_vel.z);
1690 gr_set_color_fast(&Color_bright);
1691 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,str);
1694 // blit the maneuverability
1695 gr_set_color_fast(&Color_normal);
1696 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Maneuverability",744));
1697 if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1698 gr_set_color_fast(&Color_bright);
1699 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->maneuverability_str);
1704 gr_set_color_fast(&Color_normal);
1705 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Armor",745));
1706 if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1707 gr_set_color_fast(&Color_bright);
1708 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->armor_str);
1712 // blit the gun mounts
1713 gr_set_color_fast(&Color_normal);
1714 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Gun Mounts",746));
1715 if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1716 gr_set_color_fast(&Color_bright);
1717 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->gun_mounts);
1721 // blit the missile banke
1722 gr_set_color_fast(&Color_normal);
1723 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Missile Banks",747));
1724 if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1725 gr_set_color_fast(&Color_bright);
1726 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->missile_banks);
1730 // blit the manufacturer
1731 gr_set_color_fast(&Color_normal);
1732 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start,XSTR("Manufacturer",748));
1733 if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1734 gr_set_color_fast(&Color_bright);
1735 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,sip->manufacturer_str);
1739 // blit the _short_ text description
1741 Assert(Multi_ts_ship_info_line_count < 3);
1742 gr_set_color_fast(&Color_normal);
1743 for(idx=0;idx<Multi_ts_ship_info_line_count;idx++){
1744 gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, Multi_ts_ship_info_lines[idx]);
1751 // blit the status bar
1752 void multi_ts_blit_status_bar()
1758 // mode specific text
1759 switch(Multi_ts_status_bar_mode){
1761 strcpy(text,XSTR("Ships/Weapons Locked",749));
1765 strcpy(text,XSTR("Ships/Weapons Are Now Free",750));
1770 // if we should be blitting
1772 gr_get_string_size(&text_w,NULL,text);
1773 gr_set_color_fast(&Color_bright_blue);
1774 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);
1778 // assign the correct players to the correct slots
1779 void multi_ts_init_players()
1783 // if i'm an observer, i have no ship
1784 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1785 Net_player->p_info.ship_index = -1;
1788 // initialize all players and observer
1789 for(idx=0;idx<MAX_PLAYERS;idx++){
1790 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1791 if(MULTI_OBSERVER(Net_players[idx])){
1792 Net_players[idx].p_info.ship_index = -1;
1794 Multi_ts_team[Net_players[idx].p_info.team].multi_ts_player[Net_players[idx].p_info.ship_index] = &Net_players[idx];
1800 // assign the correct objnums to the correct slots
1801 void multi_ts_init_objnums()
1803 int idx,s_idx,team_index,slot_index;
1806 // zero out the indices
1807 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1808 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1809 Multi_ts_team[idx].multi_ts_objnum[s_idx] = -1;
1813 // set all the objnums
1814 objp = GET_FIRST(&obj_used_list);
1815 while(objp != END_OF_LIST(&obj_used_list)){
1816 // if its a ship, get its slot index (if any)
1817 if(objp->type == OBJ_SHIP){
1818 multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1819 if((slot_index != -1) && (team_index != -1)){
1820 Multi_ts_team[team_index].multi_ts_objnum[slot_index] = Ships[objp->instance].objnum;
1824 objp = GET_NEXT(objp);
1828 // get the proper team and slot index for the given ship name
1829 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index)
1833 // set the return values to default values
1837 // if we're in team vs. team mode
1838 if(Netgame.type_flags & NG_TYPE_TEAM){
1839 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1840 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1841 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
1843 *slot_index = s_idx;
1849 // if we're _not_ in team vs. team mode
1851 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1852 if(!stricmp(ship_name,Multi_ts_slot_names[idx])){
1861 // function to return the shipname of the ship in the slot designated by the team and slot
1863 char *multi_ts_get_shipname( int team, int slot_index )
1865 if ( Netgame.type_flags & NG_TYPE_TEAM ) {
1866 Assert( (team >= 0) && (team < MULTI_TS_MAX_TEAMS) );
1867 return Multi_ts_slot_team_names[team][slot_index];
1869 Assert( team == 0 );
1870 return Multi_ts_slot_names[slot_index];
1874 // assign the correct flags to the correct slots
1875 void multi_ts_init_flags()
1879 // zero out the flags
1880 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1881 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1882 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_NONE;
1886 // in a team vs. team situation
1887 if(Netgame.type_flags & NG_TYPE_TEAM){
1888 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
1889 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1890 // if the there is an objnum here but no ship class, we know its currently empty
1891 if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class == -1)){
1892 Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_EMPTY;
1893 } else if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class != -1)){
1894 Multi_ts_team[idx].multi_ts_flag[s_idx] = Wss_slots_teams[idx][s_idx].ship_class;
1899 // in a non team vs. team situation
1901 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1902 // if the there is an objnum here but no ship class, we know its currently empty
1903 if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class == -1)){
1904 Multi_ts_team[0].multi_ts_flag[idx] = MULTI_TS_FLAG_EMPTY;
1905 } else if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class != -1)){
1906 Multi_ts_team[0].multi_ts_flag[idx] = Wss_slots[idx].ship_class;
1912 // handle an available ship scroll down button press
1913 void multi_ts_avail_scroll_down()
1915 if((Multi_ts_avail_count - Multi_ts_avail_start) > MULTI_TS_AVAIL_MAX_DISPLAY){
1916 gamesnd_play_iface(SND_USER_SELECT);
1917 Multi_ts_avail_start++;
1919 gamesnd_play_iface(SND_GENERAL_FAIL);
1923 // handle an available ship scroll up button press
1924 void multi_ts_avail_scroll_up()
1926 if(Multi_ts_avail_start > 0){
1927 gamesnd_play_iface(SND_USER_SELECT);
1928 Multi_ts_avail_start--;
1930 gamesnd_play_iface(SND_GENERAL_FAIL);
1934 // handle all mouse events (clicking, dragging, and dropping)
1935 void multi_ts_handle_mouse()
1937 int snazzy_region,snazzy_action;
1938 int region_type,region_index,region_empty;
1939 int mouse_x,mouse_y,ship_class;
1941 // get the mouse coords
1942 mouse_get_pos(&mouse_x,&mouse_y);
1944 // do frame for the snazzy menu
1945 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);
1951 if(snazzy_region != -1){
1952 region_type = multi_ts_region_type(snazzy_region);
1953 Assert(region_type != -1);
1955 // determine what type of region the mouse is over and the appropriate index
1956 switch(region_type){
1957 case MULTI_TS_AVAIL_LIST:
1958 region_index = multi_ts_avail_index(snazzy_region);
1959 ship_class = multi_ts_get_avail_ship_class(region_index);
1961 if(ship_class == -1){
1964 region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1;
1967 case MULTI_TS_SLOT_LIST:
1968 region_index = multi_ts_slot_index(snazzy_region);
1969 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] >= 0) ? 0 : 1;
1971 ship_class = Wss_slots[region_index].ship_class;
1974 case MULTI_TS_PLAYER_LIST:
1975 region_index = multi_ts_player_index(snazzy_region);
1976 region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL) ? 0 : 1;
1981 // maybe play a "highlight" sound
1982 switch(region_type){
1983 case MULTI_TS_PLAYER_LIST:
1984 if((Multi_ts_hotspot_index != region_index) && (region_index >= 0) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL)){
1985 gamesnd_play_iface(SND_USER_SELECT);
1990 // set the current frame mouse hotspot vars
1991 Multi_ts_hotspot_type = region_type;
1992 Multi_ts_hotspot_index = region_index;
1994 // if we currently have clicked on something and have just released it
1995 if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
1996 Multi_ts_clicked_flag = 0;
1999 // if we're currently not carrying anything and the user has clicked
2000 if(!Multi_ts_carried_flag && !Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && !region_empty){
2001 // set the "clicked" flag
2002 Multi_ts_clicked_flag = 1;
2004 // check to see if he clicked on a ship type and highlight if necessary
2005 switch(region_type){
2006 // selected a ship in the wing slots
2007 case MULTI_TS_SLOT_LIST:
2008 Multi_ts_select_type = MULTI_TS_SLOT_LIST;
2009 Multi_ts_select_index = region_index;
2010 multi_ts_select_ship();
2013 // selected a ship on the avail list
2014 case MULTI_TS_AVAIL_LIST:
2015 Multi_ts_select_type = MULTI_TS_AVAIL_LIST;
2016 Multi_ts_select_index = region_index;
2017 multi_ts_select_ship();
2020 // selected something else - unselect
2022 Multi_ts_select_type = -1;
2023 Multi_ts_select_index = -1;
2024 Multi_ts_select_ship_class = -1;
2028 Multi_ts_clicked_x = mouse_x;
2029 Multi_ts_clicked_y = mouse_y;
2032 // if we had something clicked and have started dragging it
2033 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))){
2034 // if this player is an observer, he shouldn't be able to do jack
2035 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2039 // first we check for illegal conditions (any case where he cannot grab what he is attempting to grab)
2040 switch(region_type){
2041 case MULTI_TS_AVAIL_LIST :
2042 // if players are not yet locked, can't grab ships
2043 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2051 case MULTI_TS_SLOT_LIST:
2052 // if players are not yet locked, can't grab ships
2053 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2057 if(multi_ts_disabled_slot(region_index)){
2058 multi_ts_maybe_host_only_popup();
2061 if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] < 0){
2065 case MULTI_TS_PLAYER_LIST:
2066 if(!multi_ts_can_grab_player(region_index)){
2073 Multi_ts_clicked_flag = 0;
2074 Multi_ts_carried_flag = 1;
2076 // set up the carried icon here
2077 Multi_ts_carried_from_type = region_type;
2078 Multi_ts_carried_from_index = region_index;
2079 Multi_ts_carried_ship_class = ship_class;
2082 // if we were carrying something but have dropped it
2083 if(Multi_ts_carried_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
2084 Multi_ts_carried_flag = 0;
2085 Multi_ts_clicked_flag = 0;
2087 // if we're not allowed to drop onto this slot
2088 if((region_type == MULTI_TS_SLOT_LIST) && multi_ts_disabled_slot(region_index)){
2089 multi_ts_maybe_host_only_popup();
2092 // if we're over some kind of valid region, apply
2093 multi_ts_drop(Multi_ts_carried_from_type,Multi_ts_carried_from_index,region_type,region_index,Multi_ts_carried_ship_class);
2097 // can the specified player perform the action he is attempting
2098 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2104 // get the appropriate player
2105 if(player_index == -1){
2108 pl = &Net_players[player_index];
2111 // get the operation type
2112 op_type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2114 // if either of the indices are bogus, then bail
2115 if((from_index == -1) || (to_index == -1)){
2120 case TS_GRAB_FROM_LIST:
2121 // if there are no more of this ship class, its no go
2122 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2126 // if he's not allowed to touch the wing slot
2127 if(multi_ts_disabled_slot(to_index,player_index)){
2131 // if the slot he's trying to drop it on is "permanently" empty
2132 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2137 case TS_SWAP_LIST_SLOT:
2138 // if there are no more of this ship class, its no go
2139 if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2143 // if he's not allowed to touch the wing slot
2144 if(multi_ts_disabled_slot(to_index,player_index)){
2148 // if the slot we're trying to move to is invalid, then do nothing
2149 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2153 // if the slot he's trying to drop it on is "permanently" empty
2154 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2159 case TS_SWAP_SLOT_SLOT:
2160 // if he's not allowed to touch one of the slots, its no go
2161 if(multi_ts_disabled_slot(from_index,player_index) || multi_ts_disabled_slot(to_index,player_index)){
2165 // if the slot we're taking from is invalid
2166 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2170 // if the slot he's trying to drop it on is "permanently" empty
2171 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2176 case TS_DUMP_TO_LIST:
2177 // if he's not allowed to be touching the slot to begin with, it no go
2178 if(multi_ts_disabled_slot(from_index,player_index)){
2182 // if the slot we're trying to move to is invalid, then do nothing
2183 if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2188 case TS_SWAP_PLAYER_PLAYER:
2189 // if his team is already locked, he cannot do this
2190 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2194 // if there isn't a player at one of the positions
2195 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)){
2199 // if this is not a player ship type object
2200 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2201 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2202 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2207 if(Netgame.type_flags & NG_TYPE_TEAM){
2208 // if he's not the team captain, he cannot do this
2209 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2213 // if he's not the host, he cannot do this
2214 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2220 case TS_MOVE_PLAYER:
2221 // if his team is already locked, he cannot do this
2222 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2226 // if there isn't a player at the _from_
2227 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL){
2231 // if there is no ship at the _to_ location
2232 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] < 0){
2236 // if this is not a player ship type object
2237 if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2238 pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2239 if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2244 if(Netgame.type_flags & NG_TYPE_TEAM){
2245 // if he's not the team captain, he cannot do this
2246 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2250 // if he's not the host, he cannot do this
2251 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2265 // determine the kind of drag and drop operation this is
2266 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)
2270 // get the appropriate player
2271 if(player_index == -1){
2274 pl = &Net_players[player_index];
2278 // came from the ship avail list
2279 case MULTI_TS_AVAIL_LIST :
2281 if(to_type == MULTI_TS_AVAIL_LIST){
2285 // if placing it on a slot
2286 if(to_type == MULTI_TS_SLOT_LIST){
2287 if(Wss_slots_teams[pl->p_info.team][to_index].ship_class == -1){
2288 return TS_GRAB_FROM_LIST;
2290 return TS_SWAP_LIST_SLOT;
2295 // came from the ship slots
2296 case MULTI_TS_SLOT_LIST :
2297 if(to_type == MULTI_TS_SLOT_LIST){
2298 return TS_SWAP_SLOT_SLOT;
2300 if(to_type == MULTI_TS_AVAIL_LIST){
2301 return TS_DUMP_TO_LIST;
2305 // came from the player lists
2306 case MULTI_TS_PLAYER_LIST :
2307 if(to_type == MULTI_TS_PLAYER_LIST){
2308 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL){
2309 return TS_MOVE_PLAYER;
2311 return TS_SWAP_PLAYER_PLAYER;
2320 void multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2322 int size,update,sound;
2323 ubyte wss_data[MAX_PACKET_SIZE-20];
2326 // determine what kind of operation this is
2327 int type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2329 // get the proper net player
2330 if(player_index == -1){
2333 pl = &Net_players[player_index];
2336 // set the proper pool pointers
2337 ss_set_team_pointers(pl->p_info.team);
2341 case TS_SWAP_SLOT_SLOT :
2342 nprintf(("Network","Apply swap slot slot %d %d\n",from_index,to_index));
2343 update = ss_swap_slot_slot(from_index,to_index,&sound);
2345 case TS_DUMP_TO_LIST :
2346 nprintf(("Network","Apply dump to list %d %d\n",from_index,to_index));
2347 update = ss_dump_to_list(from_index,ship_class,&sound);
2349 case TS_SWAP_LIST_SLOT :
2350 nprintf(("Network","Apply swap list slot %d %d\n",from_index,to_index));
2351 update = ss_swap_list_slot(ship_class,to_index,&sound);
2353 case TS_GRAB_FROM_LIST :
2354 nprintf(("Network","Apply grab from list %d %d\n",from_index,to_index));
2355 update = ss_grab_from_list(ship_class,to_index,&sound);
2357 case TS_SWAP_PLAYER_PLAYER :
2358 nprintf(("Network","Apply swap player player %d %d\n",from_index,to_index));
2359 update = multi_ts_swap_player_player(from_index,to_index,&sound,player_index);
2361 case TS_MOVE_PLAYER :
2362 nprintf(("Network","Apply move player %d %d\n",from_index,to_index));
2363 update = multi_ts_move_player(from_index,to_index,&sound,player_index);
2370 // if we're the host, send an update to all players
2371 if ( MULTIPLAYER_HOST ) {
2372 // send the correct type of update
2373 if(type == TS_SWAP_PLAYER_PLAYER){
2375 size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound, player_index);
2376 send_wss_update_packet(pl->p_info.team,wss_data, size);
2378 // send a player slot update packet as well, so ship class information, etc is kept correct
2379 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,-1);
2382 // if the player index == -1, it means the action was done locally - so play a sound
2383 if((player_index == -1) && (sound != -1)){
2384 gamesnd_play_iface(sound);
2388 // sync the interface screen up ourselves, if necessary
2389 if(Net_player->p_info.team == pl->p_info.team){
2390 multi_ts_sync_interface();
2393 // make sure all flags are set properly for all teams
2394 multi_ts_init_flags();
2397 // set the proper pool pointers
2398 ss_set_team_pointers(Net_player->p_info.team);
2401 // drop a carried icon
2402 void multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2404 // if I'm the host, apply immediately
2405 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2406 // if this is a legal operation
2407 if(multi_ts_can_perform(from_type,from_index,to_type,to_index,ship_class,player_index)){
2408 multi_ts_apply(from_type,from_index,to_type,to_index,ship_class,player_index);
2410 nprintf(("Network","Could not apply operation!\n"));
2413 // otherwise send a request to the host
2415 send_wss_request_packet(Net_player->player_id, from_type, from_index, to_type, to_index, -1, ship_class, WSS_SHIP_SELECT);
2419 // swap two player positions
2420 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index)
2422 net_player *pl,*temp;
2424 // get the proper player pointer
2425 if(player_index == -1){
2428 pl = &Net_players[player_index];
2432 temp = Multi_ts_team[pl->p_info.team].multi_ts_player[to_index];
2433 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2434 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = temp;
2436 // update netplayer information if necessary
2437 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2438 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2439 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;
2441 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);
2443 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2444 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2445 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;
2447 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);
2450 // update ship flags
2451 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2452 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2453 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2454 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2456 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2457 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2458 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2459 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2462 // recalcalate which slots are locked/unlocked, etc
2463 ss_recalc_multiplayer_slots();
2465 // send an update packet to all players
2466 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2467 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2468 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2471 *sound = SND_ICON_DROP;
2477 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index)
2481 // get the proper player pointer
2482 if(player_index == -1){
2485 pl = &Net_players[player_index];
2489 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2490 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = NULL;
2492 // update netplayer information if necessary
2493 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2494 Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2495 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;
2497 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);
2499 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2500 Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2501 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;
2503 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);
2506 // update ship flags
2507 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2508 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2509 if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2510 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2512 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2513 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2514 if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2515 Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2518 // recalcalate which slots are locked/unlocked, etc
2519 ss_recalc_multiplayer_slots();
2521 // send an update packet to all players
2522 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2523 send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2524 gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2527 *sound = SND_ICON_DROP;
2532 // get the ship class of the current index in the avail list or -1 if none exists
2533 int multi_ts_get_avail_ship_class(int index)
2535 int ship_count,class_index;
2537 ship_count = index + Multi_ts_avail_start;
2539 while((ship_count >= 0) && (class_index < MAX_SHIP_TYPES)){
2540 if(Ss_pool[class_index] > 0){
2544 if(ship_count >= 0){
2556 // blit the currently carried icon (if any)
2557 void multi_ts_blit_carried_icon()
2560 int offset_x,offset_y,callsign_w;
2561 char callsign[CALLSIGN_LEN+2];
2563 // if we're not carrying anything, then return
2564 if(!Multi_ts_carried_flag){
2568 // get the mouse position
2569 mouse_get_pos(&x,&y);
2571 // if we're carrying an icon of some kind
2572 switch(Multi_ts_carried_from_type){
2573 case MULTI_TS_SLOT_LIST:
2574 offset_x = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2575 offset_y = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2578 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2580 case MULTI_TS_AVAIL_LIST:
2581 offset_x = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2582 offset_y = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2585 ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2587 case MULTI_TS_PLAYER_LIST:
2588 // get the final length of the string so we can calculate a valid offset
2589 strcpy(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->player->callsign);
2590 gr_force_fit_string(callsign,CALLSIGN_LEN,Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD]);
2591 gr_get_string_size(&callsign_w,NULL,callsign);
2593 // calculate the offsets
2594 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);
2595 offset_y = Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2597 gr_set_color_fast(&Color_normal);
2598 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);
2605 // if the (console) player is allowed to grab a player slot at this point
2606 int multi_ts_can_grab_player(int slot_index, int player_index)
2610 // get a pointe rto the proper net player
2611 if(player_index == -1){
2614 pl = &Net_players[player_index];
2617 // if the players are locked in any case, he annot grab it
2618 if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2622 if(Netgame.type_flags & NG_TYPE_TEAM){
2623 // if he's not the team captain, he cannot do this
2624 if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2628 // if he's not the host, he cannot do this
2629 if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2634 // if the slot is empty
2635 if(Multi_ts_team[pl->p_info.team].multi_ts_player[slot_index] == NULL){
2642 // get the team # of the given ship
2643 int multi_ts_get_team(char *ship_name)
2647 // lookup through all team ship names
2648 for(idx=0;idx<MULTI_TS_MAX_TEAMS;idx++){
2649 for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
2650 if(!stricmp(ship_name,Multi_ts_slot_team_names[idx][s_idx])){
2656 // always on team 0 if not found otherwise
2660 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2661 int multi_ts_avail_bmap_num(int slot_index)
2663 // if this slot has been highlighted for informational purposes
2664 if((Multi_ts_select_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_select_index == slot_index)){
2665 return ICON_FRAME_SELECTED;
2668 // if its otherwise being lit by the mouse
2669 if((Multi_ts_hotspot_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_hotspot_index == slot_index)){
2670 return ICON_FRAME_HOT;
2673 return ICON_FRAME_NORMAL;
2676 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
2677 int multi_ts_slot_bmap_num(int slot_index)
2679 // special case - slot is disabled, its my ship and the host hasn't locked the ships yet
2680 if(multi_ts_disabled_high_slot(slot_index)){
2681 return ICON_FRAME_DISABLED_HIGH;
2684 // if this slot is disabled for us, then show it as such
2685 if(multi_ts_disabled_slot(slot_index)){
2686 return ICON_FRAME_DISABLED;
2689 // if this slot has been highlighted for informational purposes
2690 if((Multi_ts_select_type == MULTI_TS_SLOT_LIST) && (Multi_ts_select_index == slot_index)){
2691 return ICON_FRAME_SELECTED;
2694 // if this is our ship, then highlight it as so
2695 if(Net_player->p_info.ship_index == slot_index){
2696 return ICON_FRAME_PLAYER;
2699 // if its otherwise being lit by the mouse
2700 if((Multi_ts_hotspot_type == MULTI_TS_SLOT_LIST) && (Multi_ts_hotspot_index == slot_index)){
2701 return ICON_FRAME_HOT;
2704 // normal unhighlighted frame
2705 return ICON_FRAME_NORMAL;
2708 // select the given slot and setup any information, etc
2709 void multi_ts_select_ship()
2713 int n_chars[MAX_BRIEF_LINES];
2714 char ship_desc[1000];
2715 char *p_str[MAX_BRIEF_LINES];
2719 // blast all current text
2720 memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2721 memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2723 // get the selected ship class
2724 Assert(Multi_ts_select_index >= 0);
2725 Multi_ts_select_ship_class = -1;
2726 switch(Multi_ts_select_type){
2727 case MULTI_TS_SLOT_LIST:
2728 Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
2730 case MULTI_TS_AVAIL_LIST:
2731 Multi_ts_select_ship_class = multi_ts_get_avail_ship_class(Multi_ts_select_index);
2732 // if he has selected an empty slot, don't do anything
2733 if(Multi_ts_select_ship_class < 0){
2738 // should always have one of the 2 above types selected
2743 // split the text info up
2745 Assert(Multi_ts_select_ship_class >= 0);
2746 Assert((Ship_info[Multi_ts_select_ship_class].desc != NULL) && strlen(Ship_info[Multi_ts_select_ship_class].desc));
2748 // strip out newlines
2749 memset(ship_desc,0,1000);
2750 strcpy(ship_desc,Ship_info[Multi_ts_select_ship_class].desc);
2751 token = strtok(ship_desc,"\n");
2753 strcpy(Multi_ts_ship_info_text,token);
2754 while(token != NULL){
2755 token = strtok(NULL,"\n");
2757 strcat(Multi_ts_ship_info_text," ");
2758 strcat(Multi_ts_ship_info_text,token);
2763 if(strlen(Multi_ts_ship_info_text) > 0){
2764 // split the string into multiple lines
2765 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);
2767 // copy the split up lines into the text lines array
2768 for (idx=0;idx<n_lines;idx++ ) {
2769 Assert(n_chars[idx] < MULTI_TS_SHIP_INFO_MAX_LINE_LEN);
2770 strncpy(Multi_ts_ship_info_lines[idx], p_str[idx], n_chars[idx]);
2771 Multi_ts_ship_info_lines[idx][n_chars[idx]] = 0;
2772 drop_leading_white_space(Multi_ts_ship_info_lines[idx]);
2775 // get the line count
2776 Multi_ts_ship_info_line_count = n_lines;
2778 // set the line count to
2779 Multi_ts_ship_info_line_count = 0;
2784 // handle all details when the commit button is pressed (including possibly reporting errors/popups)
2785 void multi_ts_commit_pressed()
2787 // if my team's slots are still not "locked", we cannot commit unless we're the only player in the game
2788 if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2789 if(multi_num_players() != 1){
2790 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("Players have not yet been assigned to their ships",751));
2793 Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
2797 // check to see if its not ok for this player to commit
2798 switch(multi_ts_ok_to_commit()){
2799 // yes, it _is_ ok to commit
2801 extern void commit_pressed();
2805 // player has not assigned all necessary ships
2807 gamesnd_play_iface(SND_GENERAL_FAIL);
2808 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("You have not yet assigned all necessary ships",752));
2811 // there are ships without primary weapons
2813 gamesnd_play_iface(SND_GENERAL_FAIL);
2814 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without primary weapons!",753));
2817 // there are ships without secondary weapons
2819 gamesnd_play_iface(SND_GENERAL_FAIL);
2820 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK,XSTR("There are ships without secondary weapons!",754));
2825 // is it ok for this player to commit
2826 int multi_ts_ok_to_commit()
2829 int primary_ok,secondary_ok;
2831 // if this player is an observer, he can always commit
2832 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2836 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2837 // if this is a player slot this player can modify and it is empty, then he cannot continue
2838 // implies there is never an object in this slot
2839 if((Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2840 // implies player can't touch this slot anyway
2841 !multi_ts_disabled_slot(idx) &&
2842 // implies that there should be a player ship here but there isn't
2843 ((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)) ){
2847 // 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
2848 if( (Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2849 ((Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER) ||
2850 (Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP)) &&
2851 !multi_ts_disabled_slot(idx)){
2855 // go through all weapons in the list
2856 for(s_idx=0;s_idx<MAX_WL_WEAPONS;s_idx++){
2857 // if this slot has a weapon with a greater than 0 count, check
2858 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)){
2859 switch(Weapon_info[Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx]].subtype){
2873 // if we've got both primary and secondary weapons
2874 if(primary_ok && secondary_ok){
2879 // if the ship doesn't have primary weapons
2884 // if the ship doesn't have secondary weapons
2894 // check to see that no illegal ship settings have occurred
2895 void multi_ts_check_errors()
2901 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2902 if(Multi_ts_team[0].multi_ts_objnum[idx] == -1){
2906 shipp = &Ships[Objects[Multi_ts_team[0].multi_ts_objnum[idx]].instance];
2907 Assert((shipp->weapons.current_primary_bank != -1) && (shipp->weapons.current_secondary_bank != -1));
2913 // ------------------------------------------------------------------------------------------------------
2914 // TEAM SELECT PACKET HANDLERS
2917 // send a player slot position update
2918 void send_pslot_update_packet(int team,int code,int sound)
2920 ubyte data[MAX_PACKET_SIZE],stop,val;
2923 int packet_size = 0;
2926 // build the header and add the data
2927 BUILD_HEADER(SLOT_UPDATE);
2937 // add the sound to play
2938 s_sound = (short)sound;
2941 // add data based upon the packet code
2943 case TS_CODE_LOCK_TEAM:
2944 // don't have to do anything
2946 case TS_CODE_PLAYER_UPDATE:
2947 // only the host should ever be doing this
2948 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
2950 // add individual slot data
2951 for(idx=0;idx<MAX_WSS_SLOTS;idx++){
2952 if(Multi_ts_team[team].multi_ts_flag[idx] != MULTI_TS_FLAG_NONE){
2961 // add the ship class
2962 val = (ubyte)Wss_slots_teams[team][idx].ship_class;
2965 // add the objnum we're working with
2966 i_tmp = Multi_ts_team[team].multi_ts_objnum[idx];
2969 // add a byte indicating if a player is here or not
2970 if(Multi_ts_team[team].multi_ts_player[idx] == NULL){
2977 // if there's a player, add his address
2979 ADD_DATA(Multi_ts_team[team].multi_ts_player[idx]->player_id);
2981 // should also update his p_info settings locally
2982 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_class = Wss_slots_teams[team][idx].ship_class;
2983 Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_index = idx;
2986 // 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)
2987 if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER){
2989 } else if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP){
2997 // add a final stop byte
3006 // send the packet to the standalone
3007 if(Net_player->flags & NETINFO_FLAG_AM_MASTER) {
3008 multi_io_send_to_all_reliable(data, packet_size);
3010 multi_io_send_reliable(Net_player, data, packet_size);
3014 // process a player slot position update
3015 void process_pslot_update_packet(ubyte *data, header *hinfo)
3017 int offset = HEADER_LENGTH;
3019 int player_index,idx,team,code,objnum;
3022 ubyte stop,val,slot_num,ship_class;
3024 my_index = Net_player->p_info.ship_index;
3026 // if we're the standalone, then we should be routing this data to all the other clients
3028 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3029 // fill in the address information of where this came from
3030 player_index = find_player_id(hinfo->id);
3031 Assert(player_index != -1);
3042 // get the sound to play
3045 // process the different opcodes
3047 case TS_CODE_LOCK_TEAM:
3049 Multi_ts_team[team].multi_players_locked = 1;
3051 // if this was my team, sync stuff up
3052 if((team == Net_player->p_info.team) && !(Game_mode & GM_STANDALONE_SERVER)){
3053 multi_ts_set_status_bar_mode(1);
3054 multi_ts_sync_interface();
3055 ss_recalc_multiplayer_slots();
3058 // if this is the standalone server, we need to re-route the packet here and there
3059 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3060 // in team vs team mode, only a team captain should ever be sending this
3061 if(Netgame.type_flags & NG_TYPE_TEAM){
3062 Assert(Net_players[player_index].flags & NETINFO_FLAG_TEAM_CAPTAIN);
3064 // in any other mode, it better be coming from the game host
3066 Assert(Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST);
3069 // re-route to all other players
3070 for(idx=0;idx<MAX_PLAYERS;idx++){
3071 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
3072 multi_io_send_reliable(&Net_players[idx], data, offset);
3077 case TS_CODE_PLAYER_UPDATE:
3078 // get the first stop byte
3080 while(stop != 0xff){
3084 // get the ship class
3085 GET_DATA(ship_class);
3090 // flag indicating if a player is in this slot
3093 // look the player up
3094 GET_DATA(player_id);
3095 player_index = find_player_id(player_id);
3097 // if we couldn't find him
3098 if(player_index == -1){
3099 nprintf(("Network","Couldn't find player for pslot update!\n"));
3100 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3102 // if we found him, assign him to this ship
3104 Net_players[player_index].p_info.ship_class = (int)ship_class;
3105 Net_players[player_index].p_info.ship_index = (int)slot_num;
3106 multi_assign_player_ship(player_index,&Objects[objnum],(int)ship_class);
3109 Multi_ts_team[team].multi_ts_player[slot_num] = &Net_players[player_index];
3111 // if this was me and my ship index changed, update the weapon select screen
3112 if(my_index != Net_player->p_info.ship_index){
3113 wl_reset_selected_slot();
3115 my_index = Net_player->p_info.ship_index;
3119 Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
3122 // get the ship flag byte
3124 Objects[objnum].flags &= ~(OF_PLAYER_SHIP | OF_COULD_BE_PLAYER);
3127 Objects[objnum].flags |= OF_PLAYER_SHIP;
3130 obj_set_flags( &Objects[objnum], Objects[objnum].flags | OF_COULD_BE_PLAYER );
3134 // get the next stop byte
3137 // if we have a sound we're supposed to play
3138 if((sound != -1) && !(Game_mode & GM_STANDALONE_SERVER) && (gameseq_get_state() == GS_STATE_TEAM_SELECT)){
3139 gamesnd_play_iface(sound);
3142 // if i'm the standalone server, I should rebroadcast this packet
3143 if(Game_mode & GM_STANDALONE_SERVER){
3144 for(idx=0;idx<MAX_PLAYERS;idx++){
3145 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_HOST(Net_players[idx]) && (Net_player != &Net_players[idx])){
3146 multi_io_send_reliable(&Net_players[idx], data, offset);
3154 // recalculate stuff
3155 if(!(Game_mode & GM_STANDALONE_SERVER)){
3156 ss_recalc_multiplayer_slots();