1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "network/multiteamselect.h"
14 #include "network/multi.h"
15 #include "missionui/chatbox.h"
16 #include "gamesnd/gamesnd.h"
17 #include "io/key.h"
18 #include "globalincs/linklist.h"
19 #include "gamesequence/gamesequence.h"
20 #include "graphics/font.h"
21 #include "network/multiutil.h"
22 #include "missionui/missionscreencommon.h"
23 #include "missionui/missionshipchoice.h"
24 #include "missionui/missionweaponchoice.h"
25 #include "missionui/missionbrief.h"
26 #include "network/multimsgs.h"
27 #include "menuui/snazzyui.h"
28 #include "io/mouse.h"
29 #include "popup/popup.h"
30 #include "network/multiui.h"
31 #include "network/multi_endgame.h"
32 #include "globalincs/alphacolors.h"
33 #include "playerman/player.h"
34 #include "ship/ship.h"
35 #include "weapon/weapon.h"
36 #include "object/object.h"
37 #include "parse/parselo.h"
38 #include "mission/missionparse.h"
39 
40 
41 // ------------------------------------------------------------------------------------------------------
42 // TEAM SELECT DEFINES/VARS
43 //
44 
45 // mission screen common data
46 extern int Next_screen;
47 
48 //XSTR:OFF
49 
50 // bitmap defines
51 #define MULTI_TS_PALETTE							"InterfacePalette"
52 
53 char *Multi_ts_bitmap_fname[GR_NUM_RESOLUTIONS] = {
54 	"TeamSelect",		// GR_640
55 	"2_TeamSelect"		// GR_1024
56 };
57 
58 char *Multi_ts_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
59 	"TeamSelect-M",	// GR_640
60 	"2_TeamSelect-M"		// GR_1024
61 };
62 
63 // constants for coordinate lookup
64 #define MULTI_TS_X_COORD 0
65 #define MULTI_TS_Y_COORD 1
66 #define MULTI_TS_W_COORD 2
67 #define MULTI_TS_H_COORD 3
68 
69 #define MULTI_TS_NUM_BUTTONS						7
70 #define MULTI_TS_BRIEFING							0					// go to the briefing
71 #define MULTI_TS_SHIP_SELECT						1					// this screen
72 #define MULTI_TS_WEAPON_SELECT					2					// go to the weapon select screen
73 #define MULTI_TS_SHIPS_UP							3					// scroll the ships list up
74 #define MULTI_TS_SHIPS_DOWN						4					// scroll the ships list down
75 #define MULTI_TS_COMMIT								5					// commit
76 #define MULTI_TS_LOCK								6					// lock (free) ship/weapon select
77 
78 ui_button_info Multi_ts_buttons[GR_NUM_RESOLUTIONS][MULTI_TS_NUM_BUTTONS] = {
79 	{ // GR_640
80 		ui_button_info("CB_00",	7,		3,		37,	7,		0),
81 		ui_button_info("CB_01",	7,		19,	37,	23,	1),
82 		ui_button_info("CB_02",	7,		35,	37,	39,	2),
83 		ui_button_info("TSB_03",	5,		303,	-1,	-1,	3),
84 		ui_button_info("TSB_04",	5,		454,	-1,	-1,	4),
85 		ui_button_info("TSB_09",	571,	425,	572,	413,	9),
86 		ui_button_info("TSB_34",	603,	374,	602,	364,	34)
87 	},
88 	{ // GR_1024
89 
90 		ui_button_info("2_CB_00",	12,	5,		59,	12,	0),
91 		ui_button_info("2_CB_01",	12,	31,	59,	37,	1),
92 		ui_button_info("2_CB_02",	12,	56,	59,	62,	2),
93 		ui_button_info("2_TSB_03",	8,		485,	-1,	-1,	3),
94 		ui_button_info("2_TSB_04",	8,		727,	-1,	-1,	4),
95 		ui_button_info("2_TSB_09",	914,	681,	937,	660,	9),
96 		ui_button_info("2_TSB_34",	966,	599,	964,	584,	34)
97 	},
98 };
99 
100 
101 // players locked ani graphic
102 #define MULTI_TS_NUM_LOCKED_BITMAPS				3
103 
104 char *Multi_ts_bmap_names[GR_NUM_RESOLUTIONS][3] = {
105 	{ // GR_640
106 		"TSB_340000",
107 		"TSB_340001",
108 		"TSB_340002"
109 	},
110 	{ // GR_1024
111 		"2_TSB_340000",
112 		"2_TSB_340001",
113 		"2_TSB_340002"
114 	}
115 };
116 int Multi_ts_locked_bitmaps[MULTI_TS_NUM_LOCKED_BITMAPS];
117 
118 
119 // snazzy menu regions
120 #define TSWING_0_SHIP_0								10
121 #define TSWING_0_SHIP_1								12
122 #define TSWING_0_SHIP_2								14
123 #define TSWING_0_SHIP_3								16
124 #define TSWING_1_SHIP_0								18
125 #define TSWING_1_SHIP_1								20
126 #define TSWING_1_SHIP_2								22
127 #define TSWING_1_SHIP_3								24
128 #define TSWING_2_SHIP_0								26
129 #define TSWING_2_SHIP_1								28
130 #define TSWING_2_SHIP_2								30
131 #define TSWING_2_SHIP_3								32
132 
133 #define TSWING_0_NAME_0								11
134 #define TSWING_0_NAME_1								13
135 #define TSWING_0_NAME_2								15
136 #define TSWING_0_NAME_3								17
137 #define TSWING_1_NAME_0								19
138 #define TSWING_1_NAME_1								21
139 #define TSWING_1_NAME_2								23
140 #define TSWING_1_NAME_3								25
141 #define TSWING_2_NAME_0								27
142 #define TSWING_2_NAME_1								29
143 #define TSWING_2_NAME_2								31
144 #define TSWING_2_NAME_3								33
145 
146 #define TSWING_LIST_0								5
147 #define TSWING_LIST_1								6
148 #define TSWING_LIST_2								7
149 #define TSWING_LIST_3								8
150 
151 #define MULTI_TS_SLOT_LIST							0
152 #define MULTI_TS_PLAYER_LIST						1
153 #define MULTI_TS_AVAIL_LIST						2
154 
155 // interface data
156 #define MULTI_TS_NUM_SNAZZY_REGIONS				28
157 int Multi_ts_bitmap;
158 int Multi_ts_mask;
159 int Multi_ts_inited = 0;
160 int Multi_ts_snazzy_regions;
161 ubyte *Multi_ts_mask_data;
162 int Multi_ts_mask_w, Multi_ts_mask_h;
163 MENU_REGION	Multi_ts_region[MULTI_TS_NUM_SNAZZY_REGIONS];
164 UI_WINDOW Multi_ts_window;
165 
166 // ship slot data
167 #define MULTI_TS_NUM_SHIP_SLOTS_TEAM	4														// # of ship slots in team v team
168 #define MULTI_TS_FLAG_NONE					-2														// never has any ships
169 #define MULTI_TS_FLAG_EMPTY				-1														// currently empty
170 
171 static int Multi_ts_slot_icon_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][2] = {							// x,y
172 	{		//
173 			{128,301},		// GR_640
174 			{205,482}		// GR_1024
175 	},
176 	{		//
177 			{91,347},		// GR_640
178 			{146,555}		// GR_1024
179 	},
180 	{		//
181 			{166,347},		// GR_640
182 			{266,555}		// GR_1024
183 	},
184 	{		// alpha
185 			{128,395},		// GR_640
186 			{205,632}		// GR_1024
187 	},
188 	{		//
189 			{290,301},		// GR_640
190 			{464,482}		// GR_1024
191 	},
192 	{		//
193 			{253,347},		// GR_640
194 			{405,555}		// GR_1024
195 	},
196 	{		//
197 			{328,347},		// GR_640
198 			{525,555}		// GR_1024
199 	},
200 	{		// beta
201 			{290,395},		// GR_640
202 			{464,632}		// GR_1024
203 	},
204 	{		//
205 			{453,301},		// GR_640
206 			{725,482}		// GR_1024
207 	},
208 	{		//
209 			{416,347},		// GR_640
210 			{666,555}		// GR_1024
211 	},
212 	{		//
213 			{491,347},		// GR_640
214 			{786,555}		// GR_1024
215 	},
216 	{		// gamma
217 			{453,395},		// GR_640
218 			{725,632}		// GR_1024
219 	}
220 };
221 
222 static int Multi_ts_slot_text_coords[MULTI_TS_NUM_SHIP_SLOTS][GR_NUM_RESOLUTIONS][3] = {	// x,y,width
223 	{		// alpha
224 		{112,330,181-112},	// GR_640
225 		{187,517,181-112}		// GR_1024
226 	},
227 	{		// alpha
228 		{74,377,143-74},	// GR_640
229 		{126,592,143-74}	// GR_1024
230 	},
231 	{		// alpha
232 		{149,377,218-149},// GR_640
233 		{248,592,218-149}	// GR_1024
234 	},
235 	{		// alpha
236 		{112,424,181-112},// GR_640
237 		{187,667,181-112}	// GR_1024
238 	},
239 	{		// beta
240 		{274,330,343-274},// GR_640
241 		{446,517,343-274}	// GR_1024
242 	},
243 	{		// beta
244 		{236,377,305-236},// GR_640
245 		{385,592,305-236}	// GR_1024
246 	},
247 	{		// beta
248 		{311,377,380-311},// GR_640
249 		{507,592,380-311}	// GR_1024
250 	},
251 	{		// beta
252 		{274,424,343-274},// GR_640
253 		{446,667,343-274}	// GR_1024
254 	},
255 	{		// gamma
256 		{437,330,506-437},// GR_640
257 		{707,517,506-437}	// GR_1024
258 	},
259 	{		// gamma
260 		{399,377,468-399},// GR_640
261 		{646,592,468-399}	// GR_1024
262 	},
263 	{		// gamma
264 		{474,377,543-474},// GR_640
265 		{768,592,543-474}	// GR_1024
266 	},
267 	{		// gamma
268 		{437,424,506-437},// GR_640
269 		{707,667,506-437}	// GR_1024
270 	}
271 };
272 
273 // avail ship list data
274 #define MULTI_TS_AVAIL_MAX_DISPLAY		4
275 static int Multi_ts_avail_coords[MULTI_TS_AVAIL_MAX_DISPLAY][GR_NUM_RESOLUTIONS][2] = {							// x,y coords
276 	{		//
277 			{23,331},	// GR_640
278 			{37,530}		// GR_1024
279 	},
280 	{		//
281 			{23,361},	// GR_640
282 			{37,578}		// GR_1024
283 	},
284 	{		//
285 			{23,391},	// GR_640
286 			{37,626}		// GR_1024
287 	},
288 	{		//
289 			{23,421},	// GR_640
290 			{37,674}		// GR_1024
291 	}
292 };
293 int Multi_ts_avail_start = 0;																		// starting index of where we will display the available ships
294 int Multi_ts_avail_count = 0;																		// the # of available ship classes
295 
296 // ship information stuff
297 #define MULTI_TS_SHIP_INFO_MAX_LINE_LEN				150
298 #define MULTI_TS_SHIP_INFO_MAX_LINES					10
299 #define MULTI_TS_SHIP_INFO_MAX_TEXT						(MULTI_TS_SHIP_INFO_MAX_LINE_LEN * MULTI_TS_SHIP_INFO_MAX_LINES)
300 
301 static int Multi_ts_ship_info_coords[GR_NUM_RESOLUTIONS][3] = {
302 	{ // GR_640
303 		33, 150, 387
304 	},
305 	{ // GR_1024
306 		53, 240, 618
307 	}
308 };
309 
310 char Multi_ts_ship_info_lines[MULTI_TS_SHIP_INFO_MAX_LINES][MULTI_TS_SHIP_INFO_MAX_LINE_LEN];
311 char Multi_ts_ship_info_text[MULTI_TS_SHIP_INFO_MAX_TEXT];
312 int Multi_ts_ship_info_line_count;
313 
314 // status bar mode
315 static int Multi_ts_status_coords[GR_NUM_RESOLUTIONS][3] = {
316 	{ // GR_640
317 		95, 467, 426
318 	},
319 	{ // GR_1024
320 		152, 747, 688
321 	}
322 };
323 
324 int Multi_ts_status_bar_mode = 0;
325 
326 // carried icon information
327 int Multi_ts_carried_flag = 0;
328 int Multi_ts_clicked_flag = 0;
329 int Multi_ts_clicked_x,Multi_ts_clicked_y;
330 int Multi_ts_carried_ship_class;
331 int Multi_ts_carried_from_type = 0;
332 int Multi_ts_carried_from_index = 0;
333 
334 // selected ship types (for informational purposes)
335 int Multi_ts_select_type = -1;
336 int Multi_ts_select_index = -1;
337 int Multi_ts_select_ship_class = -1;
338 
339 // per-frame mouse hotspot vars
340 int Multi_ts_hotspot_type = -1;
341 int Multi_ts_hotspot_index = -1;
342 
343 // operation types
344 #define TS_GRAB_FROM_LIST									0
345 #define TS_SWAP_LIST_SLOT									1
346 #define TS_SWAP_SLOT_SLOT									2
347 #define TS_DUMP_TO_LIST										3
348 #define TS_SWAP_PLAYER_PLAYER								4
349 #define TS_MOVE_PLAYER										5
350 
351 // packet codes
352 #define TS_CODE_LOCK_TEAM									0						// the specified team's slots are locked
353 #define TS_CODE_PLAYER_UPDATE								1						// a player slot update for the specified team
354 
355 // team data
356 #define MULTI_TS_FLAG_NONE									-2						// slot is _always_ empty
357 #define MULTI_TS_FLAG_EMPTY								-1						// flag is temporarily empty
358 typedef struct ts_team_data {
359 	int multi_ts_objnum[MULTI_TS_NUM_SHIP_SLOTS];							// objnums for all slots in this team
360 	net_player *multi_ts_player[MULTI_TS_NUM_SHIP_SLOTS];					// net players corresponding to the same slots
361 	int multi_ts_flag[MULTI_TS_NUM_SHIP_SLOTS];								// flags indicating the "status" of a slot
362 	int multi_players_locked;														// are the players locked into place
363 } ts_team_data;
364 ts_team_data Multi_ts_team[MULTI_TS_MAX_TVT_TEAMS];								// data for all teams
365 
366 // deleted ship objnums
367 int Multi_ts_deleted_objnums[MULTI_TS_MAX_TVT_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
368 int Multi_ts_num_deleted;
369 
370 //XSTR:ON
371 
372 // ------------------------------------------------------------------------------------------------------
373 // TEAM SELECT FORWARD DECLARATIONS
374 //
375 
376 // check for button presses
377 void multi_ts_check_buttons();
378 
379 // act on a button press
380 void multi_ts_button_pressed(int n);
381 
382 // initialize all screen data, etc
383 void multi_ts_init_graphics();
384 
385 // blit all of the icons representing all wings
386 void multi_ts_blit_wings();
387 
388 // blit all of the player callsigns under the correct ships
389 void multi_ts_blit_wing_callsigns();
390 
391 // blit the ships on the avail list
392 void multi_ts_blit_avail_ships();
393 
394 // initialize the snazzy menu stuff for dragging ships,players around
395 void multi_ts_init_snazzy();
396 
397 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
398 int multi_ts_region_type(int region);
399 
400 // convert the region num to a ship slot index
401 int multi_ts_slot_index(int region);
402 
403 // convert the region num to an avail list index
404 int multi_ts_avail_index(int region);
405 
406 // convert the region num to a player slot index
407 int multi_ts_player_index(int region);
408 
409 // blit the status bar
410 void multi_ts_blit_status_bar();
411 
412 // assign the correct players to the correct slots
413 void multi_ts_init_players();
414 
415 // assign the correct objnums to the correct slots
416 void multi_ts_init_objnums();
417 
418 // assign the correct flags to the correct slots
419 void multi_ts_init_flags();
420 
421 // get the proper team and slot index for the given ship name
422 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index, bool mantis2757switch);
423 
424 // handle an available ship scroll down button press
425 void multi_ts_avail_scroll_down();
426 
427 // handle an available ship scroll up button press
428 void multi_ts_avail_scroll_up();
429 
430 // handle all mouse events (clicking, dragging, and dropping)
431 void multi_ts_handle_mouse();
432 
433 // can the specified player perform the action he is attempting
434 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index = -1);
435 
436 // determine the kind of drag and drop operation this is
437 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index = -1);
438 
439 // swap two player positions
440 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index = -1);
441 
442 // move a player
443 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index = -1);
444 
445 // get the ship class of the current index in the avail list or -1 if none exists
446 int multi_ts_get_avail_ship_class(int index);
447 
448 // blit the currently carried icon (if any)
449 void multi_ts_blit_carried_icon();
450 
451 // if the (console) player is allowed to grab a player slot at this point
452 int multi_ts_can_grab_player(int slot_index,int player_index = -1);
453 
454 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
455 int multi_ts_slot_bmap_num(int slot_index);
456 
457 // blit any active ship information text
458 void multi_ts_blit_ship_info();
459 
460 // select the given slot and setup any information, etc
461 void multi_ts_select_ship();
462 
463 // is it ok for this player to commit
464 int multi_ts_ok_to_commit();
465 
466 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
467 int multi_ts_avail_bmap_num(int slot_index);
468 
469 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
470 void multi_ts_set_status_bar_mode(int m);
471 
472 // check to see that no illegal ship settings have occurred
473 void multi_ts_check_errors();
474 
475 // ------------------------------------------------------------------------------------------------------
476 // TEAM SELECT FUNCTIONS
477 //
478 
479 // initialize the team select screen (always call, even when switching between weapon select, etc)
multi_ts_init()480 void multi_ts_init()
481 {
482 	// if we haven't initialized at all yet, then do it
483 	if(!Multi_ts_inited){
484 		multi_ts_init_graphics();
485 		Multi_ts_inited = 1;
486 	}
487 
488 	// use the common interface palette
489 	multi_common_set_palette();
490 
491 	Net_player->state = NETPLAYER_STATE_SHIP_SELECT;
492 
493 	Current_screen = ON_SHIP_SELECT;
494 }
495 
496 // initialize all critical internal data structures
multi_ts_common_init()497 void multi_ts_common_init()
498 {
499 	int idx;
500 
501 	// reset timestamps here. they seem to get hosed by the loadinh of the mission file
502 	multi_reset_timestamps();
503 
504 	// saying "not allowed to mess with ships"
505 	Multi_ts_status_bar_mode = 0;
506 
507 	// intialize ship info stuff
508 	memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
509 	memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
510 	Multi_ts_ship_info_line_count = 0;
511 
512 	// initialize carried icon information
513 	Multi_ts_carried_flag = 0;
514 	Multi_ts_clicked_flag = 0;
515 	Multi_ts_clicked_x = 0;
516 	Multi_ts_clicked_y = 0;
517 	Multi_ts_carried_ship_class = -1;
518 	Multi_ts_carried_from_type = 0;
519 	Multi_ts_carried_from_index = 0;
520 
521 	// selected slot information (should be default player ship)
522 	if(!MULTI_PERM_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
523 		Multi_ts_select_type = MULTI_TS_SLOT_LIST;
524 		Multi_ts_select_index = Net_player->p_info.ship_index;
525 
526 		// select this ship and setup his info
527 		Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
528 		multi_ts_select_ship();
529 	} else {
530 		Multi_ts_select_type = -1;
531 		Multi_ts_select_index = -1;
532 
533 		// no ship class selected for information purposes
534 		Multi_ts_select_ship_class = -1;
535 	}
536 
537 	// deleted ship information
538 	memset(Multi_ts_deleted_objnums,0,sizeof(int) * MULTI_TS_MAX_TVT_TEAMS * MULTI_TS_NUM_SHIP_SLOTS);
539 	Multi_ts_num_deleted = 0;
540 
541 	// mouse hotspot information
542 	Multi_ts_hotspot_type = -1;
543 	Multi_ts_hotspot_index = -1;
544 
545 	// initialize avail ship list data
546 	Multi_ts_avail_start = 0;
547 
548 	// load the locked button bitmaps bitmaps
549 	for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
550 		Multi_ts_locked_bitmaps[idx] = -1;
551 		Multi_ts_locked_bitmaps[idx] = bm_load(Multi_ts_bmap_names[gr_screen.res][idx]);
552 	}
553 
554 	// blast the team data clean
555 	memset(Multi_ts_team,0,sizeof(ts_team_data) * MULTI_TS_MAX_TVT_TEAMS);
556 
557 	// assign the correct players to the correct slots
558 	multi_ts_init_players();
559 
560 	// assign the correct objnums to the correct slots
561 	multi_ts_init_objnums();
562 
563 	// sync the interface as normal
564 	multi_ts_sync_interface();
565 }
566 
567 // do frame for team select
multi_ts_do()568 void multi_ts_do()
569 {
570 	int k = chatbox_process();
571 	k = Multi_ts_window.process(k);
572 
573 	// process any keypresses
574 	switch(k){
575 	case KEY_ESC :
576 		gamesnd_play_iface(SND_USER_SELECT);
577 		multi_quit_game(PROMPT_ALL);
578 		break;
579 
580 	// cycle to the weapon select screen
581 	case KEY_TAB :
582 		gamesnd_play_iface(SND_USER_SELECT);
583 		Next_screen = ON_WEAPON_SELECT;
584 		gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
585 		break;
586 
587 	case KEY_ENTER|KEY_CTRLED:
588 	//	multi_ts_commit_pressed();
589 		Commit_pressed = 1;
590 		break;
591 	}
592 
593 	// check any button presses
594 	multi_ts_check_buttons();
595 
596 	// handle all mouse related events
597 	multi_ts_handle_mouse();
598 
599 	// check for errors
600 	multi_ts_check_errors();
601 
602 	// draw the background, etc
603 	gr_reset_clip();
604 	GR_MAYBE_CLEAR_RES(Multi_ts_bitmap);
605 	if(Multi_ts_bitmap != -1){
606 		gr_set_bitmap(Multi_ts_bitmap);
607 		gr_bitmap(0,0,GR_RESIZE_MENU);
608 	}
609 	Multi_ts_window.draw();
610 
611 	// render all wings
612 	multi_ts_blit_wings();
613 
614 	// blit all callsigns
615 	multi_ts_blit_wing_callsigns();
616 
617 	// blit the ships on the available list
618 	multi_ts_blit_avail_ships();
619 
620 	// force draw the ship select button
621 	Multi_ts_buttons[gr_screen.res][MULTI_TS_SHIP_SELECT].button.draw_forced(2);
622 
623 	// force draw the "locked" button if necessary
624 	if(multi_ts_is_locked()){
625 		Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(2);
626 	} else {
627 		if( ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) ||
628 			 ((Netgame.type_flags & NG_TYPE_TEAM) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST)) ){
629 			Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw_forced(0);
630 		} else {
631 			Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.draw();
632 		}
633 	}
634 
635 	// blit any active ship information
636 	multi_ts_blit_ship_info();
637 
638 	// blit the status bar
639 	multi_ts_blit_status_bar();
640 
641 	// render the chatbox
642 	chatbox_render();
643 
644 	// render tooltips
645 	Multi_ts_window.draw_tooltip();
646 
647 	// display the status of the voice system
648 	multi_common_voice_display_status();
649 
650 	// blit any carried icons
651 	multi_ts_blit_carried_icon();
652 
653 	// flip the buffer
654 	gr_flip();
655 
656 	// If the commit button was pressed, do the commit button actions.  Done at the end of the
657 	// loop since we are a bit special and have to close out in the proper order.
658 	if ( Commit_pressed ) {
659 		multi_ts_commit_pressed();
660 		Commit_pressed = 0;
661 	}
662 }
663 
664 // close the team select screen (always call, even when switching between weapon select, etc)
multi_ts_close()665 void multi_ts_close()
666 {
667 	int idx;
668 
669 	if(!Multi_ts_inited){
670 		return;
671 	}
672 
673 	Multi_ts_inited = 0;
674 
675 	// shut down the snazzy menu
676 	snazzy_menu_close();
677 
678 	// unload any bitmaps
679 	if(!bm_unload(Multi_ts_bitmap)){
680 		nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ts_bitmap_fname[gr_screen.res]));
681 	}
682 	for(idx=0;idx<MULTI_TS_NUM_LOCKED_BITMAPS;idx++){
683 		if(Multi_ts_locked_bitmaps[idx] != -1){
684 			bm_release(Multi_ts_locked_bitmaps[idx]);
685 			Multi_ts_locked_bitmaps[idx] = -1;
686 		}
687 	}
688 
689 	// destroy the UI_WINDOW
690 	Multi_ts_window.destroy();
691 }
692 
693 // is the given slot disabled for the specified player
multi_ts_disabled_slot(int slot_num,int player_index)694 int multi_ts_disabled_slot(int slot_num, int player_index)
695 {
696 	net_player *pl;
697 
698 	// get the appropriate net player
699 	if(player_index == -1){
700 		pl = Net_player;
701 	} else {
702 		pl = &Net_players[player_index];
703 	}
704 
705 	// if the player is an observer, its _always_ disabled
706 	if(pl->flags & NETINFO_FLAG_OBSERVER){
707 		return 1;
708 	}
709 
710 	// if the flag for this team isn't set to "free" we can't do anything
711 	if(!Multi_ts_team[pl->p_info.team].multi_players_locked){
712 		return 1;
713 	}
714 
715 	// if the "leaders" only flag is set
716 	if(Netgame.options.flags & MSO_FLAG_SS_LEADERS){
717 		// in a team vs. team situation
718 		if(Netgame.type_flags & NG_TYPE_TEAM){
719 			if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
720 				return 0;
721 			}
722 		}
723 		// in a non team vs. team situation
724 		else {
725 			if(pl->flags & NETINFO_FLAG_GAME_HOST){
726 				return 0;
727 			}
728 		}
729 	} else {
730 		// in a team vs. team situation
731 		if(Netgame.type_flags & NG_TYPE_TEAM){
732 			// if i'm the team captain I can mess with my own ships as well as those of the ai ships on my team
733 			if(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN){
734 				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)){
735 					return 1;
736 				}
737 
738 				return 0;
739 			}
740 		}
741 		// in a non team vs. team situation
742 		else {
743 			// if we're the host, we can our own ship and ai ships
744 			if(pl->flags & NETINFO_FLAG_GAME_HOST){
745 				// can't grab player ships
746 				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)){
747 					return 1;
748 				}
749 
750 				return 0;
751 			}
752 		}
753 
754 		// if this is our slot, then we can grab it
755 		if(slot_num == pl->p_info.ship_index){
756 			return 0;
757 		}
758 	}
759 
760 	return 1;
761 }
762 
763 // is the given slot disabled for the specified player, _and_ it is his ship as well
multi_ts_disabled_high_slot(int slot_index,int player_index)764 int multi_ts_disabled_high_slot(int slot_index,int player_index)
765 {
766 	net_player *pl;
767 
768 	// get the appropriate net player
769 	if(player_index == -1){
770 		pl = Net_player;
771 	} else {
772 		pl = &Net_players[player_index];
773 	}
774 
775 	// if this is disabled for him and its also _his_ slot
776 	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)){
777 		return 1;
778 	}
779 
780 	return 0;
781 }
782 
783 // resynch all display/interface elements based upon all the ship/weapon pool values
multi_ts_sync_interface()784 void multi_ts_sync_interface()
785 {
786 	int idx;
787 
788 	// item 1 - determine how many ship types are available in the ship pool
789 	Multi_ts_avail_count = 0;
790 	for(idx=0;idx<Num_ship_classes;idx++){
791 		if(Ss_pool[idx] > 0){
792 			Multi_ts_avail_count++;
793 		}
794 	}
795 
796 	// item 2 - make sure our local Multi_ts_slot_flag array is up to date
797 	multi_ts_init_flags();
798 
799 	// item 3 - set/unset any necessary flags in underlying ship select data structures
800 	for(idx=0;idx<MAX_WSS_SLOTS;idx++){
801 		switch(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx]){
802 		case MULTI_TS_FLAG_EMPTY :
803 			ss_make_slot_empty(idx);
804 			break;
805 		case MULTI_TS_FLAG_NONE :
806 			break;
807 		default :
808 			ss_make_slot_full(idx);
809 			break;
810 		}
811 	}
812 
813 	// item 4 - reset the locked/unlocked status of all ships in the weapon select screen
814 	ss_recalc_multiplayer_slots();
815 }
816 
multi_ts_assign_players_all()817 void multi_ts_assign_players_all()
818 {
819 	int idx,team_index,slot_index,found,player_count,shipnum;
820 	char name_lookup[100];
821 	object *objp;
822 
823 	// set all player ship indices to -1
824 	for(idx=0;idx<MAX_PLAYERS;idx++){
825 		if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
826 			Net_players[idx].p_info.ship_index = -1;
827 		}
828 	}
829 
830 	// merge the created object list with the actual object list so we have all available ships
831 	obj_merge_created_list();
832 
833 	// get the # of players currently in the game
834 	player_count = multi_num_players();
835 
836 	// always assign the host to the wing leader of one of the TVT wings
837 	// this is valid for coop games as well because the first starting wing
838 	// and the first tvt wing must have the same name
839 	memset(name_lookup,0,100);
840 
841 	if(Netgame.type_flags & NG_TYPE_TEAM) {
842 		sprintf(name_lookup, "%s 1", TVT_wing_names[Netgame.host->p_info.team]);
843 	}
844 	else {
845 		// To account for cases where <Wingname> 1 is not a player ship
846 		for (int i = 0; i < MAX_SHIPS_PER_WING; i++) {
847 			wing_bash_ship_name(name_lookup, TVT_wing_names[0], i + 1);
848 			if (!stricmp(name_lookup, Player_start_shipname))
849 				break;
850 		}
851 	}
852 
853 	shipnum = ship_name_lookup(name_lookup);
854 
855 	// if we couldn't find the ship for the host
856 	if(shipnum == -1){
857 		// Netgame.flags |= NG_FLAG_QUITTING;
858 		multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
859 		return;
860 	}
861 
862 	multi_ts_get_team_and_slot(Ships[shipnum].ship_name,&team_index,&slot_index);
863 	multi_assign_player_ship(NET_PLAYER_INDEX(Netgame.host),&Objects[Ships[shipnum].objnum],Ships[shipnum].ship_info_index);
864 	Netgame.host->p_info.ship_index = slot_index;
865 	Assert(Netgame.host->p_info.ship_index >= 0);
866 	Netgame.host->p_info.ship_class = Ships[shipnum].ship_info_index;
867 	Netgame.host->m_player->objnum = Ships[shipnum].objnum;
868 
869 	// for each netplayer, try and find a ship
870 	objp = GET_FIRST(&obj_used_list);
871 	while(objp != END_OF_LIST(&obj_used_list)){
872 		// find a valid player ship - ignoring the ship which was assigned to the host
873 		if((objp->flags & OF_PLAYER_SHIP) && stricmp(Ships[objp->instance].ship_name,name_lookup)){
874 			// determine what team and slot this ship is
875 			multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index, true);
876 			Assert((team_index != -1) && (slot_index != -1));
877 
878 			// in a team vs. team situation
879 			if(Netgame.type_flags & NG_TYPE_TEAM){
880 				// find a player on this team who needs a ship
881 				found = 0;
882 				for(idx=0;idx<MAX_PLAYERS;idx++){
883 					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)){
884 						found = 1;
885 						break;
886 					}
887 				}
888 			}
889 			// in a non team vs. team situation
890 			else {
891 				// find any player on this who needs a ship
892 				found = 0;
893 				for(idx=0;idx<MAX_PLAYERS;idx++){
894 					if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.ship_index == -1)){
895 						found = 1;
896 						break;
897 					}
898 				}
899 			}
900 
901 			// if we found a player
902 			if(found){
903 				multi_assign_player_ship(idx,objp,Ships[objp->instance].ship_info_index);
904 				Net_players[idx].p_info.ship_index = slot_index;
905 				Assert(Net_players[idx].p_info.ship_index >= 0);
906 				Net_players[idx].p_info.ship_class = Ships[objp->instance].ship_info_index;
907 				Net_players[idx].m_player->objnum = OBJ_INDEX(objp);
908 
909 				// decrement the player count
910 				player_count--;
911 			} else {
912 				objp->flags &= ~OF_PLAYER_SHIP;
913 				obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
914 			}
915 
916 			// if we've assigned all players, we're done
917 			if(player_count <= 0){
918 				break;
919 			}
920 		}
921 
922 		// move to the next item
923 		objp = GET_NEXT(objp);
924 	}
925 
926 	// go through and change any ships marked as player ships to be COULD_BE_PLAYER
927 	if ( objp != END_OF_LIST(&obj_used_list) ) {
928 		for ( objp = GET_NEXT(objp); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
929 			if ( objp->flags & OF_PLAYER_SHIP ){
930 				objp->flags &= ~OF_PLAYER_SHIP;
931 				obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
932 			}
933 		}
934 	}
935 
936 	if(Game_mode & GM_STANDALONE_SERVER){
937 		Player_obj = NULL;
938 		//Net_player->m_player->objnum = -1;
939 	}
940 
941 	// check to make sure all players were assigned correctly
942 	for(idx=0;idx<MAX_PLAYERS;idx++){
943 		if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
944 			// if this guy never got assigned a player ship, there's a mission problem
945 			if(Net_players[idx].p_info.ship_index == -1){
946 				// Netgame.flags |= NG_FLAG_QUITTING;
947 				multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_SHIP_ASSIGN);
948 				return;
949 			}
950 		}
951 	}
952 }
953 
954 // delete ships which have been removed from the game, tidy things
multi_ts_create_wings()955 void multi_ts_create_wings()
956 {
957 	int idx,s_idx;
958 
959 	// the standalone never went through this screen so he should never call this function!
960 	// the standalone and all other clients will have this equivalent function performed whey they receive
961 	// the post_sync_data_packet!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
962 	Assert(!(Game_mode & GM_STANDALONE_SERVER));
963 
964 	// check status of all ships and delete or change ship type as necessary
965 	Multi_ts_num_deleted = 0;
966 	for(idx=0;idx<MULTI_TS_MAX_TVT_TEAMS;idx++){
967 		for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
968 			// otherwise if there's a valid ship in this spot
969 			if(Multi_ts_team[idx].multi_ts_flag[s_idx] >= 0){
970 				int objnum;
971 
972 				// set the ship type appropriately
973 				Assert(Wss_slots_teams[idx][s_idx].ship_class >= 0);
974 
975 				objnum = Multi_ts_team[idx].multi_ts_objnum[s_idx];
976 				change_ship_type(Objects[objnum].instance,Wss_slots_teams[idx][s_idx].ship_class);
977 
978 				// set the ship weapons correctly
979 				wl_update_ship_weapons(objnum,&Wss_slots_teams[idx][s_idx]);
980 
981 				// assign ts_index of the ship to point to the proper Wss_slots slot
982 				Ships[Objects[objnum].instance].ts_index = s_idx;
983 			} else if(Multi_ts_team[idx].multi_ts_flag[s_idx] == MULTI_TS_FLAG_EMPTY){
984 				Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] >= 0);
985 
986 				// mark the object as having been deleted
987 				Multi_ts_deleted_objnums[Multi_ts_num_deleted] = Multi_ts_team[idx].multi_ts_objnum[s_idx];
988 
989 				// delete the ship
990 				ship_add_exited_ship( &Ships[Objects[Multi_ts_deleted_objnums[Multi_ts_num_deleted]].instance], SEF_PLAYER_DELETED );
991 				obj_delete(Multi_ts_deleted_objnums[Multi_ts_num_deleted]);
992 				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]);
993 
994 				// increment the # of ships deleted
995 				Multi_ts_num_deleted++;
996 			}
997 		}
998 	}
999 }
1000 
1001 // do any necessary processing for players who have left the game
multi_ts_handle_player_drop()1002 void multi_ts_handle_player_drop()
1003 {
1004 	int idx,s_idx;
1005 
1006 	// find the player
1007 	for(idx=0;idx<MULTI_TS_MAX_TVT_TEAMS;idx++){
1008 		for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1009 			// if we found him, clear his player slot and set his object back to being  OF_COULD_BE_PLAYER
1010 			if((Multi_ts_team[idx].multi_ts_player[s_idx] != NULL) && !MULTI_CONNECTED((*Multi_ts_team[idx].multi_ts_player[s_idx]))){
1011 				Assert(Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1);
1012 				Multi_ts_team[idx].multi_ts_player[s_idx] = NULL;
1013 				Objects[Multi_ts_team[idx].multi_ts_objnum[s_idx]].flags &= ~(OF_PLAYER_SHIP);
1014 				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);
1015 			}
1016 		}
1017 	}
1018 }
1019 
1020 // set the status bar to reflect the status of wing slots (free or not free). 0 or 1 are valid values for now
multi_ts_set_status_bar_mode(int m)1021 void multi_ts_set_status_bar_mode(int m)
1022 {
1023 	Multi_ts_status_bar_mode = m;
1024 }
1025 
1026 // the "lock" button has been pressed
multi_ts_lock_pressed()1027 void multi_ts_lock_pressed()
1028 {
1029 	// do nothing if the button has already been pressed
1030 	if(multi_ts_is_locked()){
1031 		gamesnd_play_iface(SND_GENERAL_FAIL);
1032 		return;
1033 	}
1034 
1035 	if(Netgame.type_flags & NG_TYPE_TEAM){
1036 		Assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
1037 	} else {
1038 		Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1039 	}
1040 	gamesnd_play_iface(SND_USER_SELECT);
1041 
1042 	// send a final player slot update packet
1043 	send_pslot_update_packet(Net_player->p_info.team,TS_CODE_LOCK_TEAM,-1);
1044 	Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
1045 
1046 	// sync interface stuff
1047 	multi_ts_set_status_bar_mode(1);
1048 	multi_ts_sync_interface();
1049 	ss_recalc_multiplayer_slots();
1050 
1051 	// disable this button now
1052 	Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1053 }
1054 
1055 // if i'm "locked"
multi_ts_is_locked()1056 int multi_ts_is_locked()
1057 {
1058 	return Multi_ts_team[Net_player->p_info.team].multi_players_locked;
1059 }
1060 
1061 // show a popup saying "only host and team captains can modify, etc, etc"
multi_ts_maybe_host_only_popup()1062 void multi_ts_maybe_host_only_popup()
1063 {
1064 /*
1065 	// if this is because the "host modifies" option is set
1066 				if((Netgame.options.flags & MSO_FLAG_SS_LEADERS) && !(Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1067 					multi_ts_host_only_popup();
1068 				}
1069 
1070 	if(Netgame.type == NG_TYPE_TEAM){
1071 		popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only team captains may modify ships and weapons in this game");
1072 	} else {
1073 		popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,"Only the host may modify ships and weapons in this game");
1074 	}
1075 	*/
1076 }
1077 
1078 
1079 // ------------------------------------------------------------------------------------------------------
1080 // TEAM SELECT FORWARD DEFINITIONS
1081 //
1082 
1083 // check for button presses
multi_ts_check_buttons()1084 void multi_ts_check_buttons()
1085 {
1086 	int idx;
1087 	for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1088 		// we only really need to check for one button pressed at a time, so we can break after
1089 		// finding one.
1090 		if(Multi_ts_buttons[gr_screen.res][idx].button.pressed()){
1091 			multi_ts_button_pressed(idx);
1092 			break;
1093 		}
1094 	}
1095 }
1096 
1097 // act on a button press
multi_ts_button_pressed(int n)1098 void multi_ts_button_pressed(int n)
1099 {
1100 	switch(n){
1101 	// back to the briefing screen
1102 	case MULTI_TS_BRIEFING :
1103 		gamesnd_play_iface(SND_USER_SELECT);
1104 		Next_screen = ON_BRIEFING_SELECT;
1105 		gameseq_post_event( GS_EVENT_START_BRIEFING );
1106 		break;
1107 	// already on this screen
1108 	case MULTI_TS_SHIP_SELECT:
1109 		gamesnd_play_iface(SND_GENERAL_FAIL);
1110 		break;
1111 	// back to the weapon select screen
1112 	case MULTI_TS_WEAPON_SELECT:
1113 		gamesnd_play_iface(SND_USER_SELECT);
1114 		Next_screen = ON_WEAPON_SELECT;
1115 		gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
1116 		break;
1117 	// scroll the available ships list down
1118 	case MULTI_TS_SHIPS_DOWN:
1119 		multi_ts_avail_scroll_down();
1120 		break;
1121 	// scroll the available ships list up
1122 	case MULTI_TS_SHIPS_UP:
1123 		multi_ts_avail_scroll_up();
1124 		break;
1125 	// free ship/weapon select
1126 	case MULTI_TS_LOCK:
1127 		Assert(Game_mode & GM_MULTIPLAYER);
1128 		// the "lock" button has been pressed
1129 		multi_ts_lock_pressed();
1130 
1131 		// disable the button if it is now locked
1132 		if(multi_ts_is_locked()){
1133 			Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1134 		}
1135 		break;
1136 	// commit button
1137 	case MULTI_TS_COMMIT :
1138 	//	multi_ts_commit_pressed();
1139 		Commit_pressed = 1;
1140 		break;
1141 	default :
1142 		gamesnd_play_iface(SND_GENERAL_FAIL);
1143 		break;
1144 	}
1145 }
1146 
1147 // initialize all screen data, etc
multi_ts_init_graphics()1148 void multi_ts_init_graphics()
1149 {
1150 	int idx;
1151 
1152 	// create the interface window
1153 	Multi_ts_window.create(0,0,gr_screen.max_w_unscaled,gr_screen.max_h_unscaled,0);
1154 	Multi_ts_window.set_mask_bmap(Multi_ts_bitmap_mask_fname[gr_screen.res]);
1155 
1156 	// load the background bitmap
1157 	Multi_ts_bitmap = bm_load(Multi_ts_bitmap_fname[gr_screen.res]);
1158 	if(Multi_ts_bitmap < 0){
1159 		// we failed to load the bitmap - this is very bad
1160 		Int3();
1161 	}
1162 
1163 	// create the interface buttons
1164 	for(idx=0;idx<MULTI_TS_NUM_BUTTONS;idx++){
1165 		// create the object
1166 		if((idx == MULTI_TS_SHIPS_UP) || (idx == MULTI_TS_SHIPS_DOWN)){
1167 			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);
1168 		} else {
1169 			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);
1170 		}
1171 
1172 		// set the sound to play when highlighted
1173 		Multi_ts_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1174 
1175 		// set the ani for the button
1176 		Multi_ts_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ts_buttons[gr_screen.res][idx].filename);
1177 
1178 		// set the hotspot
1179 		Multi_ts_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ts_buttons[gr_screen.res][idx].hotspot);
1180 	}
1181 
1182 	// add some text
1183 	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);
1184 	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);
1185 	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);
1186 	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);
1187 	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);
1188 
1189 //	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);
1190 //	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);
1191 
1192 
1193 
1194 	// make the ship scrolling lists
1195 
1196 	// if we're not the host of the game (or a tema captain in team vs. team mode), disable the lock button
1197 	if (Netgame.type_flags & NG_TYPE_TEAM) {
1198 		if(!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
1199 			Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1200 		}
1201 	} else {
1202 		if(!(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1203 			Multi_ts_buttons[gr_screen.res][MULTI_TS_LOCK].button.disable();
1204 		}
1205 	}
1206 
1207 	// initialize the snazzy menu stuff (for grabbing ships, names, etc)
1208 	multi_ts_init_snazzy();
1209 
1210 	// create the chatbox (again, should not be necessary at this point)
1211 	chatbox_create();
1212 
1213 	// sync the interface as normal
1214 	multi_ts_sync_interface();
1215 }
1216 
1217 // blit all of the icons representing all wings
multi_ts_blit_wings()1218 void multi_ts_blit_wings()
1219 {
1220 	int idx;
1221 
1222 	// blit them all blindly for now
1223 	for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1224 		// if this ship doesn't exist, then continue
1225 		if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1226 			continue;
1227 		}
1228 
1229 		// otherwise blit the ship icon or the "empty" icon
1230 		if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_EMPTY){
1231 			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);
1232 		} else {
1233 			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));
1234 
1235 			// if this is a team vs team game, and the slot is occupised by a team captain, put a c there
1236 			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)){
1237 				gr_set_color_fast(&Color_bright);
1238 				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), GR_RESIZE_MENU);  // [[ Team captain ]]
1239 			}
1240 		}
1241 	}
1242 }
1243 
1244 // blit all of the player callsigns under the correct ships
multi_ts_blit_wing_callsigns()1245 void multi_ts_blit_wing_callsigns()
1246 {
1247 	int idx,callsign_w;
1248 	char callsign[CALLSIGN_LEN+2];
1249 	p_object *pobj;
1250 
1251 	// blit them all blindly for now
1252 	for(idx=0;idx<MAX_WSS_SLOTS;idx++){
1253 		// if this ship doesn't exist, then continue
1254 		if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[idx] == MULTI_TS_FLAG_NONE){
1255 			continue;
1256 		}
1257 
1258 		// if there is a player in the slot
1259 		if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
1260 			// make sure the string fits
1261 			strcpy_s(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->m_player->callsign);
1262 		} else {
1263 			// determine if this is a locked AI ship
1264 			pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
1265 			if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
1266 				strcpy_s(callsign, NOX("<"));
1267 				strcat_s(callsign, XSTR("AI",738));  // [[ Artificial Intellegence ]]
1268 				strcat_s(callsign, NOX(">"));
1269 			} else {
1270 				strcpy_s(callsign, XSTR("AI",738));  // [[ Artificial Intellegence ]]
1271 			}
1272 		}
1273 
1274 		gr_force_fit_string(callsign, CALLSIGN_LEN, Multi_ts_slot_text_coords[idx][gr_screen.res][MULTI_TS_W_COORD]);
1275 
1276 		// get the final length
1277 		gr_get_string_size(&callsign_w, NULL, callsign);
1278 
1279 		// blit the string
1280 		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)){
1281 			gr_set_color_fast(&Color_text_active_hi);
1282 		} else {
1283 			gr_set_color_fast(&Color_normal);
1284 		}
1285 		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,GR_RESIZE_MENU);
1286 	}
1287 }
1288 
1289 // blit the ships on the avail list
multi_ts_blit_avail_ships()1290 void multi_ts_blit_avail_ships()
1291 {
1292 	int display_count,ship_count,idx;
1293 	char count[6];
1294 
1295 	// blit the availability of all ship counts
1296 	display_count = 0;
1297 	ship_count = 0;
1298 	for(idx=0;idx<Num_ship_classes;idx++){
1299 		if(Ss_pool[idx] > 0){
1300 			// if our starting display index is after this, then skip it
1301 			if(ship_count < Multi_ts_avail_start){
1302 				ship_count++;
1303 			} else {
1304 				// blit the icon
1305 				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));
1306 
1307 				// blit the ship count available
1308 				sprintf(count,"%d",Ss_pool[idx]);
1309 				gr_set_color_fast(&Color_normal);
1310 				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,GR_RESIZE_MENU);
1311 
1312 				// increment the counts
1313 				display_count++;
1314 				ship_count++;
1315 			}
1316 		}
1317 
1318 		// if we've reached the max amount we can display, then stop
1319 		if(display_count >= MULTI_TS_AVAIL_MAX_DISPLAY){
1320 			return;
1321 		}
1322 	}
1323 }
1324 
1325 // initialize the snazzy menu stuff for dragging ships,players around
multi_ts_init_snazzy()1326 void multi_ts_init_snazzy()
1327 {
1328 	// initialize the snazzy menu
1329 	snazzy_menu_init();
1330 
1331 	// blast the data
1332 	Multi_ts_snazzy_regions = 0;
1333 	memset(Multi_ts_region,0,sizeof(MENU_REGION) * MULTI_TS_NUM_SNAZZY_REGIONS);
1334 
1335 	// get a pointer to the mask bitmap data
1336 	Multi_ts_mask_data = Multi_ts_window.get_mask_data(&Multi_ts_mask_w, &Multi_ts_mask_h);
1337 
1338 	// add the wing slots information
1339 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_SHIP_0,		0);
1340 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_SHIP_1,		0);
1341 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_SHIP_2,		0);
1342 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_SHIP_3,		0);
1343 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_SHIP_0,		0);
1344 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_SHIP_1,		0);
1345 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_SHIP_2,		0);
1346 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_SHIP_3,		0);
1347 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_SHIP_0,		0);
1348 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_SHIP_1,		0);
1349 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_SHIP_2,		0);
1350 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_SHIP_3,		0);
1351 
1352 	// add the name slots information
1353 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_NAME_0,		0);
1354 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_NAME_1,		0);
1355 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_NAME_2,		0);
1356 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_0_NAME_3,		0);
1357 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_NAME_0,		0);
1358 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_NAME_1,		0);
1359 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_NAME_2,		0);
1360 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_1_NAME_3,		0);
1361 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_NAME_0,		0);
1362 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_NAME_1,		0);
1363 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_NAME_2,		0);
1364 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_2_NAME_3,		0);
1365 
1366 	// add the available ships region
1367 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_LIST_0,		0);
1368 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_LIST_1,		0);
1369 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_LIST_2,		0);
1370 	snazzy_menu_add_region(&Multi_ts_region[Multi_ts_snazzy_regions++], "",	TSWING_LIST_3,		0);
1371 }
1372 
1373 // what type of region the index is (0 == ship avail list, 1 == ship slots, 2 == player slot)
multi_ts_region_type(int region)1374 int multi_ts_region_type(int region)
1375 {
1376 	if((region == TSWING_0_SHIP_0) || (region == TSWING_0_SHIP_1) || (region == TSWING_0_SHIP_2) || (region == TSWING_0_SHIP_3) ||
1377 		(region == TSWING_1_SHIP_0) || (region == TSWING_1_SHIP_1) || (region == TSWING_1_SHIP_2) || (region == TSWING_1_SHIP_3) ||
1378 		(region == TSWING_2_SHIP_0) || (region == TSWING_2_SHIP_1) || (region == TSWING_2_SHIP_2) || (region == TSWING_2_SHIP_3) ){
1379 		return MULTI_TS_SLOT_LIST;
1380 	}
1381 
1382 	if((region == TSWING_0_NAME_0) || (region == TSWING_0_NAME_1) || (region == TSWING_0_NAME_2) || (region == TSWING_0_NAME_3) ||
1383 		(region == TSWING_1_NAME_0) || (region == TSWING_1_NAME_1) || (region == TSWING_1_NAME_2) || (region == TSWING_1_NAME_3) ||
1384 		(region == TSWING_2_NAME_0) || (region == TSWING_2_NAME_1) || (region == TSWING_2_NAME_2) || (region == TSWING_2_NAME_3) ){
1385 		return MULTI_TS_PLAYER_LIST;
1386 	}
1387 
1388 	if((region == TSWING_LIST_0) || (region == TSWING_LIST_1) || (region == TSWING_LIST_2) || (region == TSWING_LIST_3)){
1389 		return MULTI_TS_AVAIL_LIST;
1390 	}
1391 
1392 	return -1;
1393 }
1394 
1395 // convert the region num to a ship slot index
multi_ts_slot_index(int region)1396 int multi_ts_slot_index(int region)
1397 {
1398 	switch(region){
1399 	case TSWING_0_SHIP_0:
1400 		return 0;
1401 	case TSWING_0_SHIP_1:
1402 		return 1;
1403 	case TSWING_0_SHIP_2:
1404 		return 2;
1405 	case TSWING_0_SHIP_3:
1406 		return 3;
1407 	case TSWING_1_SHIP_0:
1408 		return 4;
1409 	case TSWING_1_SHIP_1:
1410 		return 5;
1411 	case TSWING_1_SHIP_2:
1412 		return 6;
1413 	case TSWING_1_SHIP_3:
1414 		return 7;
1415 	case TSWING_2_SHIP_0:
1416 		return 8;
1417 	case TSWING_2_SHIP_1:
1418 		return 9;
1419 	case TSWING_2_SHIP_2:
1420 		return 10;
1421 	case TSWING_2_SHIP_3:
1422 		return 11;
1423 	}
1424 
1425 	return -1;
1426 }
1427 
1428 // convert the region num to an avail list index (starting from absolute 0)
multi_ts_avail_index(int region)1429 int multi_ts_avail_index(int region)
1430 {
1431 	switch(region){
1432 	case TSWING_LIST_0:
1433 		return 0;
1434 	case TSWING_LIST_1:
1435 		return 1;
1436 	case TSWING_LIST_2:
1437 		return 2;
1438 	case TSWING_LIST_3:
1439 		return 3;
1440 	}
1441 
1442 	return -1;
1443 }
1444 
1445 // convert the region num to a player slot index
multi_ts_player_index(int region)1446 int multi_ts_player_index(int region)
1447 {
1448 	switch(region){
1449 	case TSWING_0_NAME_0:
1450 		return 0;
1451 	case TSWING_0_NAME_1:
1452 		return 1;
1453 	case TSWING_0_NAME_2:
1454 		return 2;
1455 	case TSWING_0_NAME_3:
1456 		return 3;
1457 	case TSWING_1_NAME_0:
1458 		return 4;
1459 	case TSWING_1_NAME_1:
1460 		return 5;
1461 	case TSWING_1_NAME_2:
1462 		return 6;
1463 	case TSWING_1_NAME_3:
1464 		return 7;
1465 	case TSWING_2_NAME_0:
1466 		return 8;
1467 	case TSWING_2_NAME_1:
1468 		return 9;
1469 	case TSWING_2_NAME_2:
1470 		return 10;
1471 	case TSWING_2_NAME_3:
1472 		return 11;
1473 	}
1474 
1475 	return -1;
1476 }
1477 
1478 // blit any active ship information text
multi_ts_blit_ship_info()1479 void multi_ts_blit_ship_info()
1480 {
1481 	int y_start;
1482 	ship_info *sip;
1483 	char str[100];
1484 
1485 	// if we don't have a valid ship selected, do nothing
1486 	if(Multi_ts_select_ship_class == -1){
1487 		return;
1488 	}
1489 
1490 	// get the ship class
1491 	sip = &Ship_info[Multi_ts_select_ship_class];
1492 
1493 	// starting line
1494 	y_start = Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_Y_COORD];
1495 
1496 	memset(str,0,100);
1497 
1498 	// blit the ship class (name)
1499 	gr_set_color_fast(&Color_normal);
1500 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Class",739), GR_RESIZE_MENU);
1501 	if(strlen((sip->alt_name[0]) ? sip->alt_name : sip->name)){
1502 		gr_set_color_fast(&Color_bright);
1503 
1504 		// Goober5000
1505 		char temp[NAME_LENGTH];
1506 		strcpy_s(temp, (sip->alt_name[0]) ? sip->alt_name : sip->name);
1507 		end_string_at_first_hash_symbol(temp);
1508 
1509 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, temp, GR_RESIZE_MENU);
1510 	}
1511 	y_start += 10;
1512 
1513 	// blit the ship type
1514 	gr_set_color_fast(&Color_normal);
1515 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Type",740), GR_RESIZE_MENU);
1516 	if((sip->type_str != NULL) && strlen(sip->type_str)){
1517 		gr_set_color_fast(&Color_bright);
1518 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->type_str, GR_RESIZE_MENU);
1519 	}
1520 	y_start += 10;
1521 
1522 	// blit the ship length
1523 	gr_set_color_fast(&Color_normal);
1524 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Length",741), GR_RESIZE_MENU);
1525 	if((sip->ship_length != NULL) && strlen(sip->ship_length)){
1526 		gr_set_color_fast(&Color_bright);
1527 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->ship_length, GR_RESIZE_MENU);
1528 	}
1529 	y_start += 10;
1530 
1531 	// blit the max velocity
1532 	gr_set_color_fast(&Color_normal);
1533 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Max Velocity",742), GR_RESIZE_MENU);
1534 	sprintf(str, XSTR("%d m/s",743),(int)sip->max_vel.xyz.z);
1535 	gr_set_color_fast(&Color_bright);
1536 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start,str,GR_RESIZE_MENU);
1537 	y_start += 10;
1538 
1539 	// blit the maneuverability
1540 	gr_set_color_fast(&Color_normal);
1541 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Maneuverability",744), GR_RESIZE_MENU);
1542 	if((sip->maneuverability_str != NULL) && strlen(sip->maneuverability_str)){
1543 		gr_set_color_fast(&Color_bright);
1544 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->maneuverability_str, GR_RESIZE_MENU);
1545 	}
1546 	y_start += 10;
1547 
1548 	// blit the armor
1549 	gr_set_color_fast(&Color_normal);
1550 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Armor",745), GR_RESIZE_MENU);
1551 	if((sip->armor_str != NULL) && strlen(sip->armor_str)){
1552 		gr_set_color_fast(&Color_bright);
1553 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->armor_str, GR_RESIZE_MENU);
1554 	}
1555 	y_start += 10;
1556 
1557 	// blit the gun mounts
1558 	gr_set_color_fast(&Color_normal);
1559 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Gun Mounts",746), GR_RESIZE_MENU);
1560 	if((sip->gun_mounts != NULL) && strlen(sip->gun_mounts)){
1561 		gr_set_color_fast(&Color_bright);
1562 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->gun_mounts, GR_RESIZE_MENU);
1563 	}
1564 	y_start += 10;
1565 
1566 	// blit the missile banke
1567 	gr_set_color_fast(&Color_normal);
1568 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Missile Banks",747), GR_RESIZE_MENU);
1569 	if((sip->missile_banks != NULL) && strlen(sip->missile_banks)){
1570 		gr_set_color_fast(&Color_bright);
1571 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->missile_banks, GR_RESIZE_MENU);
1572 	}
1573 	y_start += 10;
1574 
1575 	// blit the manufacturer
1576 	gr_set_color_fast(&Color_normal);
1577 	gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, XSTR("Manufacturer",748), GR_RESIZE_MENU);
1578 	if((sip->manufacturer_str != NULL) && strlen(sip->manufacturer_str)){
1579 		gr_set_color_fast(&Color_bright);
1580 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD] + 150, y_start, sip->manufacturer_str, GR_RESIZE_MENU);
1581 	}
1582 	y_start += 10;
1583 
1584 	// blit the _short_ text description
1585 
1586 	Assert(Multi_ts_ship_info_line_count < 3);
1587 	gr_set_color_fast(&Color_normal);
1588 	for(int idx=0;idx<Multi_ts_ship_info_line_count;idx++){
1589 		gr_string(Multi_ts_ship_info_coords[gr_screen.res][MULTI_TS_X_COORD], y_start, Multi_ts_ship_info_lines[idx], GR_RESIZE_MENU);
1590 		y_start += 10;
1591 	}
1592 
1593 }
1594 
1595 
1596 // blit the status bar
multi_ts_blit_status_bar()1597 void multi_ts_blit_status_bar()
1598 {
1599 	char text[50];
1600 	int text_w;
1601 	int blit = 0;
1602 
1603 	// mode specific text
1604 	switch(Multi_ts_status_bar_mode){
1605 	case 0 :
1606 		strcpy_s(text, XSTR("Ships/Weapons Locked",749));
1607 		blit = 1;
1608 		break;
1609 	case 1 :
1610 		strcpy_s(text, XSTR("Ships/Weapons Are Now Free",750));
1611 		blit = 1;
1612 		break;
1613 	}
1614 
1615 	// if we should be blitting
1616 	if(blit){
1617 		gr_get_string_size(&text_w,NULL,text);
1618 		gr_set_color_fast(&Color_bright_blue);
1619 		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,GR_RESIZE_MENU);
1620 	}
1621 }
1622 
1623 // assign the correct players to the correct slots
multi_ts_init_players()1624 void multi_ts_init_players()
1625 {
1626 	int idx;
1627 
1628 	// if i'm an observer, i have no ship
1629 	if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1630 		Net_player->p_info.ship_index = -1;
1631 	}
1632 
1633 	// initialize all players and observer
1634 	for(idx=0;idx<MAX_PLAYERS;idx++){
1635 		if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1636 			if(MULTI_OBSERVER(Net_players[idx])){
1637 				Net_players[idx].p_info.ship_index = -1;
1638 			} else {
1639 				Multi_ts_team[Net_players[idx].p_info.team].multi_ts_player[Net_players[idx].p_info.ship_index] = &Net_players[idx];
1640 			}
1641 		}
1642 	}
1643 }
1644 
1645 // assign the correct objnums to the correct slots
multi_ts_init_objnums()1646 void multi_ts_init_objnums()
1647 {
1648 	int idx,s_idx,team_index,slot_index;
1649 	object *objp;
1650 
1651 	// zero out the indices
1652 	for(idx=0;idx<MULTI_TS_MAX_TVT_TEAMS;idx++){
1653 		for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1654 			Multi_ts_team[idx].multi_ts_objnum[s_idx] = -1;
1655 		}
1656 	}
1657 
1658 	// set all the objnums
1659 	objp = GET_FIRST(&obj_used_list);
1660 	while(objp != END_OF_LIST(&obj_used_list)){
1661 		// if its a ship, get its slot index (if any)
1662 		if(objp->type == OBJ_SHIP){
1663 			multi_ts_get_team_and_slot(Ships[objp->instance].ship_name,&team_index,&slot_index);
1664 			if((slot_index != -1) && (team_index != -1)){
1665 				Multi_ts_team[team_index].multi_ts_objnum[slot_index] = Ships[objp->instance].objnum;
1666 			}
1667 		}
1668 
1669 		objp = GET_NEXT(objp);
1670 	}
1671 }
1672 
multi_ts_validate_ship(char * shipname,char * wingname)1673 bool multi_ts_validate_ship(char *shipname, char *wingname)
1674 {
1675 	int wing_number, wing_idx;
1676 
1677 	// check name isn't too short to be valid
1678 	if (strlen(shipname) < (strlen (wingname) + 2) ) {
1679 		return false;
1680 	}
1681 
1682 	wing_idx = wing_lookup(wingname);
1683 	Assert (wing_idx >= 0 && wing_idx < MAX_WINGS);
1684 	wing_number = atoi(shipname+strlen(wingname));
1685 
1686 	if (wing_number > 0 && wing_number <= Wings[wing_idx].wave_count) {
1687 		return true;
1688 	}
1689 
1690 	return false;
1691 }
1692 
1693 // get the proper team and slot index for the given ship name
multi_ts_get_team_and_slot(char * ship_name,int * team_index,int * slot_index,bool mantis2757switch)1694 void multi_ts_get_team_and_slot(char *ship_name,int *team_index,int *slot_index, bool mantis2757switch)
1695 {
1696 	int idx;
1697 
1698 	// set the return values to default values
1699 	*team_index = -1;
1700 	*slot_index = -1;
1701 
1702 	// if we're in team vs. team mode
1703 	if(Netgame.type_flags & NG_TYPE_TEAM){
1704 		Assert(MAX_TVT_WINGS == MULTI_TS_MAX_TVT_TEAMS);
1705 		for (idx = 0; idx < MAX_TVT_WINGS; idx++) {
1706 			// get team (wing)
1707 			if ( !strnicmp(ship_name, TVT_wing_names[idx], strlen(TVT_wing_names[idx])) && multi_ts_validate_ship(ship_name, TVT_wing_names[idx]) ) {
1708 				*team_index = idx;
1709 				*slot_index = (ship_name[strlen(ship_name)-1] - '1');
1710 
1711 				// just Assert(), if this is wrong then we're pretty much screwed either way
1712 				Assert( (*slot_index >= 0) && (*slot_index < MAX_WSS_SLOTS) );
1713 			}
1714 		}
1715 	}
1716 	// if we're _not_ in team vs. team mode
1717 	else {
1718 		int wing, ship;
1719 		for (idx = 0; idx < MAX_STARTING_WINGS; idx++) {
1720 			// get wing
1721 			if ( !strnicmp(ship_name, Starting_wing_names[idx], strlen(Starting_wing_names[idx])) && multi_ts_validate_ship(ship_name, Starting_wing_names[idx]) ) {
1722 				wing = idx;
1723 				ship = (ship_name[strlen(ship_name)-1] - '1');
1724 
1725 				// just Assert(), if this is wrong then we're pretty much screwed either way
1726 				Assert( (ship >= 0) && (ship < MULTI_TS_NUM_SHIP_SLOTS_TEAM) );
1727 
1728 				// team is 0, slot is the starting slot for all ships
1729 				*team_index = 0;
1730 				*slot_index = wing * MULTI_TS_NUM_SHIP_SLOTS_TEAM + ship;
1731 			}
1732 		}
1733 	}
1734 	if(mantis2757switch)
1735 		Assert((*team_index != -1) && (*slot_index != -1)); // For tracking down Mantis 2757 - Valathil
1736 }
1737 
1738 // function to return the shipname of the ship in the slot designated by the team and slot
1739 // parameters
multi_ts_get_shipname(char * ship_name,int team,int slot_index)1740 void multi_ts_get_shipname( char *ship_name, int team, int slot_index )
1741 {
1742 	if ( Netgame.type_flags & NG_TYPE_TEAM ) {
1743 		Assert( (team >= 0) && (team < MULTI_TS_MAX_TVT_TEAMS) );
1744 		wing_bash_ship_name(ship_name, TVT_wing_names[team], slot_index);
1745 	} else {
1746 		Assert( team == 0 );
1747 		wing_bash_ship_name(ship_name, Starting_wing_names[slot_index / MULTI_TS_NUM_SHIP_SLOTS_TEAM], slot_index % MULTI_TS_NUM_SHIP_SLOTS_TEAM);
1748 	}
1749 }
1750 
1751 // assign the correct flags to the correct slots
multi_ts_init_flags()1752 void multi_ts_init_flags()
1753 {
1754 	int idx,s_idx;
1755 
1756 	// zero out the flags
1757 	for(idx=0;idx<MULTI_TS_MAX_TVT_TEAMS;idx++){
1758 		for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS;s_idx++){
1759 			Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_NONE;
1760 		}
1761 	}
1762 
1763 	// in a team vs. team situation
1764 	if(Netgame.type_flags & NG_TYPE_TEAM){
1765 		for(idx=0;idx<MULTI_TS_MAX_TVT_TEAMS;idx++){
1766 			for(s_idx=0;s_idx<MULTI_TS_NUM_SHIP_SLOTS_TEAM;s_idx++){
1767 				// if the there is an objnum here but no ship class, we know its currently empty
1768 				if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class == -1)){
1769 					Multi_ts_team[idx].multi_ts_flag[s_idx] = MULTI_TS_FLAG_EMPTY;
1770 				} else if((Multi_ts_team[idx].multi_ts_objnum[s_idx] != -1) && (Wss_slots_teams[idx][s_idx].ship_class != -1)){
1771 					Multi_ts_team[idx].multi_ts_flag[s_idx] = Wss_slots_teams[idx][s_idx].ship_class;
1772 				}
1773 			}
1774 		}
1775 	}
1776 	// in a non team vs. team situation
1777 	else {
1778 		for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
1779 			// if the there is an objnum here but no ship class, we know its currently empty
1780 			if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class == -1)){
1781 				Multi_ts_team[0].multi_ts_flag[idx] = MULTI_TS_FLAG_EMPTY;
1782 			} else if((Multi_ts_team[0].multi_ts_objnum[idx] != -1) && (Wss_slots[idx].ship_class != -1)){
1783 				Multi_ts_team[0].multi_ts_flag[idx] = Wss_slots[idx].ship_class;
1784 			}
1785 		}
1786 	}
1787 }
1788 
1789 // handle an available ship scroll down button press
multi_ts_avail_scroll_down()1790 void multi_ts_avail_scroll_down()
1791 {
1792 	if((Multi_ts_avail_count - Multi_ts_avail_start) > MULTI_TS_AVAIL_MAX_DISPLAY){
1793 		gamesnd_play_iface(SND_USER_SELECT);
1794 		Multi_ts_avail_start++;
1795 	} else {
1796 		gamesnd_play_iface(SND_GENERAL_FAIL);
1797 	}
1798 }
1799 
1800 // handle an available ship scroll up button press
multi_ts_avail_scroll_up()1801 void multi_ts_avail_scroll_up()
1802 {
1803 	if(Multi_ts_avail_start > 0){
1804 		gamesnd_play_iface(SND_USER_SELECT);
1805 		Multi_ts_avail_start--;
1806 	} else {
1807 		gamesnd_play_iface(SND_GENERAL_FAIL);
1808 	}
1809 }
1810 
1811 // handle all mouse events (clicking, dragging, and dropping)
multi_ts_handle_mouse()1812 void multi_ts_handle_mouse()
1813 {
1814 	int snazzy_region,snazzy_action;
1815 	int region_type,region_index,region_empty;
1816 	int mouse_x,mouse_y,ship_class;
1817 
1818 	// get the mouse coords
1819 	mouse_get_pos_unscaled(&mouse_x,&mouse_y);
1820 
1821 	// do frame for the snazzy menu
1822 	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);
1823 
1824 	region_type = -1;
1825 	region_index = -1;
1826 	region_empty = 1;
1827 	ship_class = -1;
1828 	if(snazzy_region != -1){
1829 		region_type = multi_ts_region_type(snazzy_region);
1830 		Assert(region_type != -1);
1831 
1832 		// determine what type of region the mouse is over and the appropriate index
1833 		switch(region_type){
1834 		case MULTI_TS_AVAIL_LIST:
1835 			region_index = multi_ts_avail_index(snazzy_region);
1836 			ship_class = multi_ts_get_avail_ship_class(region_index);
1837 
1838 			if(ship_class == -1){
1839 				region_empty = 1;
1840 			} else {
1841 				region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1;
1842 			}
1843 			break;
1844 		case MULTI_TS_SLOT_LIST:
1845 			region_index = multi_ts_slot_index(snazzy_region);
1846 			region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] >= 0) ? 0 : 1;
1847 			if(!region_empty){
1848 				ship_class = Wss_slots[region_index].ship_class;
1849 			}
1850 			break;
1851 		case MULTI_TS_PLAYER_LIST:
1852 			region_index = multi_ts_player_index(snazzy_region);
1853 			region_empty = (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL) ? 0 : 1;
1854 			break;
1855 		}
1856 	}
1857 
1858 	// maybe play a "highlight" sound
1859 	switch(region_type){
1860 	case MULTI_TS_PLAYER_LIST:
1861 		if((Multi_ts_hotspot_index != region_index) && (region_index >= 0) && (Multi_ts_team[Net_player->p_info.team].multi_ts_player[region_index] != NULL)){
1862 			gamesnd_play_iface(SND_USER_SELECT);
1863 		}
1864 		break;
1865 	}
1866 
1867 	// set the current frame mouse hotspot vars
1868 	Multi_ts_hotspot_type = region_type;
1869 	Multi_ts_hotspot_index = region_index;
1870 
1871 	// if we currently have clicked on something and have just released it
1872 	if(!Multi_ts_carried_flag && Multi_ts_clicked_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
1873 		Multi_ts_clicked_flag = 0;
1874 	}
1875 
1876 	// if we're currently not carrying anything and the user has clicked
1877 	if(!Multi_ts_carried_flag && !Multi_ts_clicked_flag && mouse_down(MOUSE_LEFT_BUTTON) && !region_empty){
1878 		// set the "clicked" flag
1879 		Multi_ts_clicked_flag = 1;
1880 
1881 		// check to see if he clicked on a ship type and highlight if necessary
1882 		switch(region_type){
1883 		// selected a ship in the wing slots
1884 		case MULTI_TS_SLOT_LIST:
1885 			Multi_ts_select_type = MULTI_TS_SLOT_LIST;
1886 			Multi_ts_select_index = region_index;
1887 			multi_ts_select_ship();
1888 			break;
1889 
1890 		// selected a ship on the avail list
1891 		case MULTI_TS_AVAIL_LIST:
1892 			Multi_ts_select_type = MULTI_TS_AVAIL_LIST;
1893 			Multi_ts_select_index = region_index;
1894 			multi_ts_select_ship();
1895 			break;
1896 
1897 		// selected something else - unselect
1898 		default :
1899 			Multi_ts_select_type = -1;
1900 			Multi_ts_select_index = -1;
1901 			Multi_ts_select_ship_class = -1;
1902 			break;
1903 		}
1904 
1905 		Multi_ts_clicked_x = mouse_x;
1906 		Multi_ts_clicked_y = mouse_y;
1907 	}
1908 
1909 	// if we had something clicked and have started dragging it
1910 	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))){
1911 		// if this player is an observer, he shouldn't be able to do jack
1912 		if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1913 			return;
1914 		}
1915 
1916 		// first we check for illegal conditions (any case where he cannot grab what he is attempting to grab)
1917 		switch(region_type){
1918 		case MULTI_TS_AVAIL_LIST :
1919 			// if players are not yet locked, can't grab ships
1920 			if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
1921 				return;
1922 			}
1923 
1924 			if(region_empty){
1925 				return;
1926 			}
1927 			break;
1928 		case MULTI_TS_SLOT_LIST:
1929 			// if players are not yet locked, can't grab ships
1930 			if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
1931 				return;
1932 			}
1933 
1934 			if(multi_ts_disabled_slot(region_index)){
1935 				multi_ts_maybe_host_only_popup();
1936 				return;
1937 			}
1938 			if(Multi_ts_team[Net_player->p_info.team].multi_ts_flag[region_index] < 0){
1939 				return;
1940 			}
1941 			break;
1942 		case MULTI_TS_PLAYER_LIST:
1943 			if(!multi_ts_can_grab_player(region_index)){
1944 				return;
1945 			}
1946 			break;
1947 		}
1948 
1949 
1950 		Multi_ts_clicked_flag = 0;
1951 		Multi_ts_carried_flag = 1;
1952 
1953 		// set up the carried icon here
1954 		Multi_ts_carried_from_type = region_type;
1955 		Multi_ts_carried_from_index = region_index;
1956 		Multi_ts_carried_ship_class = ship_class;
1957 	}
1958 
1959 	// if we were carrying something but have dropped it
1960 	if(Multi_ts_carried_flag && !mouse_down(MOUSE_LEFT_BUTTON)){
1961 		Multi_ts_carried_flag = 0;
1962 		Multi_ts_clicked_flag = 0;
1963 
1964 		// if we're not allowed to drop onto this slot
1965 		if((region_type == MULTI_TS_SLOT_LIST) && multi_ts_disabled_slot(region_index)){
1966 			multi_ts_maybe_host_only_popup();
1967 		}
1968 
1969 		// if we're over some kind of valid region, apply
1970 		multi_ts_drop(Multi_ts_carried_from_type,Multi_ts_carried_from_index,region_type,region_index,Multi_ts_carried_ship_class);
1971 	}
1972 }
1973 
1974 // can the specified player perform the action he is attempting
multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)1975 int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
1976 {
1977 	net_player *pl;
1978 	int op_type;
1979 	p_object *pobj;
1980 
1981 	// get the appropriate player
1982 	if(player_index == -1){
1983 		pl = Net_player;
1984 	} else {
1985 		pl = &Net_players[player_index];
1986 	}
1987 
1988 	// get the operation type
1989 	op_type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
1990 
1991 	// if either of the indices are bogus, then bail
1992 	if((from_index == -1) || (to_index == -1)){
1993 		return 0;
1994 	}
1995 
1996 	switch(op_type){
1997 	case TS_GRAB_FROM_LIST:
1998 		// if there are no more of this ship class, its no go
1999 		if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2000 			return 0;
2001 		}
2002 
2003 		// if he's not allowed to touch the wing slot
2004 		if(multi_ts_disabled_slot(to_index,player_index)){
2005 			return 0;
2006 		}
2007 
2008 		// if the slot he's trying to drop it on is "permanently" empty
2009 		if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2010 			return 0;
2011 		}
2012 		break;
2013 
2014 	case TS_SWAP_LIST_SLOT:
2015 		// if there are no more of this ship class, its no go
2016 		if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){
2017 			return 0;
2018 		}
2019 
2020 		// if he's not allowed to touch the wing slot
2021 		if(multi_ts_disabled_slot(to_index,player_index)){
2022 			return 0;
2023 		}
2024 
2025 		// if the slot we're trying to move to is invalid, then do nothing
2026 		if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2027 			return 0;
2028 		}
2029 		break;
2030 
2031 	case TS_SWAP_SLOT_SLOT:
2032 		// if he's not allowed to touch one of the slots, its no go
2033 		if(multi_ts_disabled_slot(from_index,player_index) || multi_ts_disabled_slot(to_index,player_index)){
2034 			return 0;
2035 		}
2036 
2037 		// if the slot we're taking from is invalid
2038 		if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2039 			return 0;
2040 		}
2041 		break;
2042 
2043 	case TS_DUMP_TO_LIST:
2044 		// if he's not allowed to be touching the slot to begin with, it no go
2045 		if(multi_ts_disabled_slot(from_index,player_index)){
2046 			return 0;
2047 		}
2048 
2049 		// if the slot we're trying to move to is invalid, then do nothing
2050 		if(Multi_ts_team[pl->p_info.team].multi_ts_flag[to_index] == MULTI_TS_FLAG_NONE){
2051 			return 0;
2052 		}
2053 		break;
2054 
2055 	case TS_SWAP_PLAYER_PLAYER:
2056 		// if his team is already locked, he cannot do this
2057 		if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2058 			return 0;
2059 		}
2060 
2061 		// if there isn't a player at one of the positions
2062 		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)){
2063 			return 0;
2064 		}
2065 
2066 		// if this is not a player ship type object
2067 		if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2068 			pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2069 			if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2070 				return 0;
2071 			}
2072 		}
2073 
2074 		if(Netgame.type_flags & NG_TYPE_TEAM){
2075 			// if he's not the team captain, he cannot do this
2076 			if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2077 				return 0;
2078 			}
2079 		} else {
2080 			// if he's not the host, he cannot do this
2081 			if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2082 				return 0;
2083 			}
2084 		}
2085 		break;
2086 
2087 	case TS_MOVE_PLAYER:
2088 		// if his team is already locked, he cannot do this
2089 		if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2090 			return 0;
2091 		}
2092 
2093 		// if there isn't a player at the _from_
2094 		if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] == NULL){
2095 			return 0;
2096 		}
2097 
2098 		// if there is no ship at the _to_ location
2099 		if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] < 0){
2100 			return 0;
2101 		}
2102 
2103 		// if this is not a player ship type object
2104 		if(Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index] != -1){
2105 			pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].instance].ship_name);
2106 			if((pobj == NULL) || !(pobj->flags & OF_PLAYER_SHIP)){
2107 				return 0;
2108 			}
2109 		}
2110 
2111 		if(Netgame.type_flags & NG_TYPE_TEAM){
2112 			// if he's not the team captain, he cannot do this
2113 			if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2114 				return 0;
2115 			}
2116 		} else {
2117 			// if he's not the host, he cannot do this
2118 			if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2119 				return 0;
2120 			}
2121 		}
2122 		break;
2123 
2124 	default :
2125 		return 0;
2126 		break;
2127 	}
2128 
2129 	return 1;
2130 }
2131 
2132 // determine the kind of drag and drop operation this is
multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)2133 int multi_ts_get_dnd_type(int from_type,int from_index,int to_type,int to_index,int player_index)
2134 {
2135 	net_player *pl;
2136 
2137 	// get the appropriate player
2138 	if(player_index == -1){
2139 		pl = Net_player;
2140 	} else {
2141 		pl = &Net_players[player_index];
2142 	}
2143 
2144 	switch(from_type){
2145 	// came from the ship avail list
2146 	case MULTI_TS_AVAIL_LIST :
2147 		// do nothing
2148 		if(to_type == MULTI_TS_AVAIL_LIST){
2149 			return -1;
2150 		}
2151 
2152 		// if placing it on a slot
2153 		if(to_type == MULTI_TS_SLOT_LIST){
2154 			if(Wss_slots_teams[pl->p_info.team][to_index].ship_class == -1){
2155 				return TS_GRAB_FROM_LIST;
2156 			} else {
2157 				return TS_SWAP_LIST_SLOT;
2158 			}
2159 		}
2160 		break;
2161 
2162 	// came from the ship slots
2163 	case MULTI_TS_SLOT_LIST :
2164 		if(to_type == MULTI_TS_SLOT_LIST){
2165 			return TS_SWAP_SLOT_SLOT;
2166 		}
2167 		if(to_type == MULTI_TS_AVAIL_LIST){
2168 			return TS_DUMP_TO_LIST;
2169 		}
2170 		break;
2171 
2172 	// came from the player lists
2173 	case MULTI_TS_PLAYER_LIST :
2174 		if(to_type == MULTI_TS_PLAYER_LIST){
2175 			if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] == NULL){
2176 				return TS_MOVE_PLAYER;
2177 			} else {
2178 				return TS_SWAP_PLAYER_PLAYER;
2179 			}
2180 		}
2181 		break;
2182 	}
2183 
2184 	return -1;
2185 }
2186 
multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)2187 void multi_ts_apply(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2188 {
2189 	int size,update,sound;
2190 	ubyte wss_data[MAX_PACKET_SIZE-20];
2191 	net_player *pl;
2192 
2193 	// determine what kind of operation this is
2194 	int type = multi_ts_get_dnd_type(from_type,from_index,to_type,to_index,player_index);
2195 
2196 	// get the proper net player
2197 	if(player_index == -1){
2198 		pl = Net_player;
2199 	} else {
2200 		pl = &Net_players[player_index];
2201 	}
2202 
2203 	// set the proper pool pointers
2204 	common_set_team_pointers(pl->p_info.team);
2205 
2206 	sound = -1;
2207 	switch(type){
2208 	case TS_SWAP_SLOT_SLOT :
2209 		nprintf(("Network","Apply swap slot slot %d %d\n",from_index,to_index));
2210 		update = ss_swap_slot_slot(from_index,to_index,&sound);
2211 		break;
2212 	case TS_DUMP_TO_LIST	:
2213 		nprintf(("Network","Apply dump to list %d %d\n",from_index,to_index));
2214 		update = ss_dump_to_list(from_index,ship_class,&sound);
2215 		break;
2216 	case TS_SWAP_LIST_SLOT :
2217 		nprintf(("Network","Apply swap list slot %d %d\n",from_index,to_index));
2218 		update = ss_swap_list_slot(ship_class,to_index,&sound);
2219 		break;
2220 	case TS_GRAB_FROM_LIST :
2221 		nprintf(("Network","Apply grab from list %d %d\n",from_index,to_index));
2222 		update = ss_grab_from_list(ship_class,to_index,&sound);
2223 		break;
2224 	case TS_SWAP_PLAYER_PLAYER :
2225 		nprintf(("Network","Apply swap player player %d %d\n",from_index,to_index));
2226 		update = multi_ts_swap_player_player(from_index,to_index,&sound,player_index);
2227 		break;
2228 	case TS_MOVE_PLAYER :
2229 		nprintf(("Network","Apply move player %d %d\n",from_index,to_index));
2230 		update = multi_ts_move_player(from_index,to_index,&sound,player_index);
2231 		break;
2232 	default :
2233 		update = 0;
2234 		break;
2235 	}
2236 
2237 	if(update){
2238 		// if we're the host, send an update to all players
2239 		if ( MULTIPLAYER_HOST ) {
2240 			// send the correct type of update
2241 			if(type == TS_SWAP_PLAYER_PLAYER){
2242 			} else {
2243 				size = store_wss_data(wss_data, MAX_PACKET_SIZE-20, sound, player_index);
2244 				send_wss_update_packet(pl->p_info.team,wss_data, size);
2245 
2246 				// send a player slot update packet as well, so ship class information, etc is kept correct
2247 				send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,-1);
2248 			}
2249 
2250 			// if the player index == -1, it means the action was done locally - so play a sound
2251 			if((player_index == -1) && (sound != -1)){
2252 				gamesnd_play_iface(sound);
2253 			}
2254 		}
2255 
2256 		// sync the interface screen up ourselves, if necessary
2257 		if(Net_player->p_info.team == pl->p_info.team){
2258 			multi_ts_sync_interface();
2259 		}
2260 
2261 		// make sure all flags are set properly for all teams
2262 		multi_ts_init_flags();
2263 	}
2264 
2265 	// set the proper pool pointers
2266 	common_set_team_pointers(Net_player->p_info.team);
2267 }
2268 
2269 // drop a carried icon
multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)2270 void multi_ts_drop(int from_type,int from_index,int to_type,int to_index,int ship_class,int player_index)
2271 {
2272 	// if I'm the host, apply immediately
2273 	if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2274 		// if this is a legal operation
2275 		if(multi_ts_can_perform(from_type,from_index,to_type,to_index,ship_class,player_index)){
2276 			multi_ts_apply(from_type,from_index,to_type,to_index,ship_class,player_index);
2277 		} else {
2278 			nprintf(("Network","Could not apply operation!\n"));
2279 		}
2280 	}
2281 	// otherwise send a request to the host
2282 	else {
2283 		send_wss_request_packet(Net_player->player_id, from_type, from_index, to_type, to_index, -1, ship_class, WSS_SHIP_SELECT);
2284 	}
2285 }
2286 
2287 // swap two player positions
multi_ts_swap_player_player(int from_index,int to_index,int * sound,int player_index)2288 int multi_ts_swap_player_player(int from_index,int to_index,int *sound,int player_index)
2289 {
2290 	net_player *pl,*temp;
2291 
2292 	// get the proper player pointer
2293 	if(player_index == -1){
2294 		pl = Net_player;
2295 	} else {
2296 		pl = &Net_players[player_index];
2297 	}
2298 
2299 	// swap the players
2300 	temp = Multi_ts_team[pl->p_info.team].multi_ts_player[to_index];
2301 	Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2302 	Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = temp;
2303 
2304 	// update netplayer information if necessary
2305 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2306 		Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2307 		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;
2308 
2309 		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);
2310 	}
2311 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2312 		Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2313 		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;
2314 
2315 		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);
2316 	}
2317 
2318 	// update ship flags
2319 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2320 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2321 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2322 		Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2323 	}
2324 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2325 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2326 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2327 		Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2328 	}
2329 
2330 	// recalcalate which slots are locked/unlocked, etc
2331 	ss_recalc_multiplayer_slots();
2332 
2333 	// send an update packet to all players
2334 	if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2335 		send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2336 		gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2337 	}
2338 
2339 	*sound = SND_ICON_DROP;
2340 
2341 	return 1;
2342 }
2343 
2344 // move a player
multi_ts_move_player(int from_index,int to_index,int * sound,int player_index)2345 int multi_ts_move_player(int from_index,int to_index,int *sound,int player_index)
2346 {
2347 	net_player *pl;
2348 
2349 	// get the proper player pointer
2350 	if(player_index == -1){
2351 		pl = Net_player;
2352 	} else {
2353 		pl = &Net_players[player_index];
2354 	}
2355 
2356 	// swap the players
2357 	Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] = Multi_ts_team[pl->p_info.team].multi_ts_player[from_index];
2358 	Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] = NULL;
2359 
2360 	// update netplayer information if necessary
2361 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2362 		Multi_ts_team[pl->p_info.team].multi_ts_player[from_index]->p_info.ship_index = from_index;
2363 		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;
2364 
2365 		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);
2366 	}
2367 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2368 		Multi_ts_team[pl->p_info.team].multi_ts_player[to_index]->p_info.ship_index = to_index;
2369 		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;
2370 
2371 		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);
2372 	}
2373 
2374 	// update ship flags
2375 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_COULD_BE_PLAYER);
2376 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags &= ~(OF_PLAYER_SHIP);
2377 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[to_index] != NULL){
2378 		Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[to_index]].flags |= OF_PLAYER_SHIP;
2379 	}
2380 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_COULD_BE_PLAYER);
2381 	Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags &= ~(OF_PLAYER_SHIP);
2382 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[from_index] != NULL){
2383 		Objects[Multi_ts_team[pl->p_info.team].multi_ts_objnum[from_index]].flags |= OF_PLAYER_SHIP;
2384 	}
2385 
2386 	// recalcalate which slots are locked/unlocked, etc
2387 	ss_recalc_multiplayer_slots();
2388 
2389 	// send an update packet to all players
2390 	if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2391 		send_pslot_update_packet(pl->p_info.team,TS_CODE_PLAYER_UPDATE,SND_ICON_DROP_ON_WING);
2392 		gamesnd_play_iface(SND_ICON_DROP_ON_WING);
2393 	}
2394 
2395 	*sound = SND_ICON_DROP;
2396 
2397 	return 1;
2398 }
2399 
2400 // get the ship class of the current index in the avail list or -1 if none exists
multi_ts_get_avail_ship_class(int index)2401 int multi_ts_get_avail_ship_class(int index)
2402 {
2403 	int ship_count,class_index;
2404 
2405 	ship_count = index + Multi_ts_avail_start;
2406 	class_index = 0;
2407 	while((ship_count >= 0) && (class_index < MAX_SHIP_CLASSES)){
2408 		if(Ss_pool[class_index] > 0){
2409 			ship_count--;
2410 		}
2411 
2412 		if(ship_count >= 0){
2413 			class_index++;
2414 		}
2415 	}
2416 
2417 	if(ship_count < 0){
2418 		return class_index;
2419 	}
2420 
2421 	return -1;
2422 }
2423 
2424 // blit the currently carried icon (if any)
multi_ts_blit_carried_icon()2425 void multi_ts_blit_carried_icon()
2426 {
2427 	int x,y;
2428 	int offset_x,offset_y,callsign_w;
2429 	char callsign[CALLSIGN_LEN+2];
2430 
2431 	// if we're not carrying anything, then return
2432 	if(!Multi_ts_carried_flag){
2433 		return;
2434 	}
2435 
2436 	// get the mouse position
2437 	mouse_get_pos_unscaled(&x,&y);
2438 
2439 	// if we're carrying an icon of some kind
2440 	switch(Multi_ts_carried_from_type){
2441 	case MULTI_TS_SLOT_LIST:
2442 		offset_x = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2443 		offset_y = Multi_ts_slot_icon_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2444 
2445 		// blit the icon
2446 		ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2447 		break;
2448 	case MULTI_TS_AVAIL_LIST:
2449 		offset_x = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_X_COORD] - Multi_ts_clicked_x;
2450 		offset_y = Multi_ts_avail_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2451 
2452 		// blit the icon
2453 		ss_blit_ship_icon(x + offset_x,y + offset_y,Multi_ts_carried_ship_class,0);
2454 		break;
2455 	case MULTI_TS_PLAYER_LIST:
2456 		// get the final length of the string so we can calculate a valid offset
2457 		strcpy_s(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->m_player->callsign);
2458 		gr_force_fit_string(callsign,CALLSIGN_LEN,Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_W_COORD]);
2459 		gr_get_string_size(&callsign_w,NULL,callsign);
2460 
2461 		// calculate the offsets
2462 		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);
2463 		offset_y = Multi_ts_slot_text_coords[Multi_ts_carried_from_index][gr_screen.res][MULTI_TS_Y_COORD] - Multi_ts_clicked_y;
2464 
2465 		gr_set_color_fast(&Color_normal);
2466 		gr_string(x + offset_x,y + offset_y,Multi_ts_team[Net_player->p_info.team].multi_ts_player[Multi_ts_carried_from_index]->m_player->callsign,GR_RESIZE_MENU);
2467 		break;
2468 	default :
2469 		break;
2470 	}
2471 }
2472 
2473 // if the (console) player is allowed to grab a player slot at this point
multi_ts_can_grab_player(int slot_index,int player_index)2474 int multi_ts_can_grab_player(int slot_index, int player_index)
2475 {
2476 	net_player *pl;
2477 
2478 	// get a pointe rto the proper net player
2479 	if(player_index == -1){
2480 		pl = Net_player;
2481 	} else {
2482 		pl = &Net_players[player_index];
2483 	}
2484 
2485 	// if the players are locked in any case, he annot grab it
2486 	if(Multi_ts_team[pl->p_info.team].multi_players_locked){
2487 		return 0;
2488 	}
2489 
2490 	if(Netgame.type_flags & NG_TYPE_TEAM){
2491 		// if he's not the team captain, he cannot do this
2492 		if(!(pl->flags & NETINFO_FLAG_TEAM_CAPTAIN)){
2493 			return 0;
2494 		}
2495 	} else {
2496 		// if he's not the host, he cannot do this
2497 		if(!(pl->flags & NETINFO_FLAG_GAME_HOST)){
2498 			return 0;
2499 		}
2500 	}
2501 
2502 	// if the slot is empty
2503 	if(Multi_ts_team[pl->p_info.team].multi_ts_player[slot_index] == NULL){
2504 		return 0;
2505 	}
2506 
2507 	return 1;
2508 }
2509 
2510 // get the team # of the given ship
multi_ts_get_team(char * ship_name)2511 int multi_ts_get_team(char *ship_name)
2512 {
2513 	int idx;//,s_idx;
2514 
2515 	// lookup through all team ship names
2516 	Assert(MAX_TVT_WINGS == MULTI_TS_MAX_TVT_TEAMS);
2517 	for(idx=0;idx<MAX_TVT_WINGS;idx++)
2518 	{
2519 		if (!strnicmp(ship_name, TVT_wing_names[idx], strlen(TVT_wing_names[idx])))
2520 			return idx;
2521 	}
2522 
2523 	// always on team 0 if not found otherwise
2524 	return 0;
2525 }
2526 
2527 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
multi_ts_avail_bmap_num(int slot_index)2528 int multi_ts_avail_bmap_num(int slot_index)
2529 {
2530 	// if this slot has been highlighted for informational purposes
2531 	if((Multi_ts_select_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_select_index == slot_index)){
2532 		return ICON_FRAME_SELECTED;
2533 	}
2534 
2535 	// if its otherwise being lit by the mouse
2536 	if((Multi_ts_hotspot_type == MULTI_TS_AVAIL_LIST) && (Multi_ts_hotspot_index == slot_index)){
2537 		return ICON_FRAME_HOT;
2538 	}
2539 
2540 	return ICON_FRAME_NORMAL;
2541 }
2542 
2543 // return the bitmap index into the ships icon array (in ship select) which should be displayed for the given slot
multi_ts_slot_bmap_num(int slot_index)2544 int multi_ts_slot_bmap_num(int slot_index)
2545 {
2546 	// special case - slot is disabled, its my ship and the host hasn't locked the ships yet
2547 	if(multi_ts_disabled_high_slot(slot_index)){
2548 		return ICON_FRAME_DISABLED_HIGH;
2549 	}
2550 
2551 	// if this slot is disabled for us, then show it as such
2552 	if(multi_ts_disabled_slot(slot_index)){
2553 		return ICON_FRAME_DISABLED;
2554 	}
2555 
2556 	// if this slot has been highlighted for informational purposes
2557 	if((Multi_ts_select_type == MULTI_TS_SLOT_LIST) && (Multi_ts_select_index == slot_index)){
2558 		return ICON_FRAME_SELECTED;
2559 	}
2560 
2561 	// if this is our ship, then highlight it as so
2562 	if(Net_player->p_info.ship_index == slot_index){
2563 		return ICON_FRAME_PLAYER;
2564 	}
2565 
2566 	// if its otherwise being lit by the mouse
2567 	if((Multi_ts_hotspot_type == MULTI_TS_SLOT_LIST) && (Multi_ts_hotspot_index == slot_index)){
2568 		return ICON_FRAME_HOT;
2569 	}
2570 
2571 	// normal unhighlighted frame
2572 	return ICON_FRAME_NORMAL;
2573 }
2574 
2575 // select the given slot and setup any information, etc
multi_ts_select_ship()2576 void multi_ts_select_ship()
2577 {
2578 	int n_lines;
2579 	int n_chars[MAX_BRIEF_LINES];
2580 	char ship_desc[1000];
2581 	const char *p_str[MAX_BRIEF_LINES];
2582 	char *token;
2583 
2584 
2585 	// blast all current text
2586 	memset(Multi_ts_ship_info_lines,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2587 	memset(Multi_ts_ship_info_text,0,MULTI_TS_SHIP_INFO_MAX_TEXT);
2588 
2589 	// get the selected ship class
2590 	Assert(Multi_ts_select_index >= 0);
2591 	Multi_ts_select_ship_class = -1;
2592 	switch(Multi_ts_select_type){
2593 	case MULTI_TS_SLOT_LIST:
2594 		Multi_ts_select_ship_class = Wss_slots[Multi_ts_select_index].ship_class;
2595 		break;
2596 	case MULTI_TS_AVAIL_LIST:
2597 		Multi_ts_select_ship_class = multi_ts_get_avail_ship_class(Multi_ts_select_index);
2598 		// if he has selected an empty slot, don't do anything
2599 		if(Multi_ts_select_ship_class < 0){
2600 			return;
2601 		}
2602 		break;
2603 	default :
2604 		// should always have one of the 2 above types selected
2605 		Int3();
2606 		break;
2607 	}
2608 
2609 	// split the text info up
2610 
2611 	Assert(Multi_ts_select_ship_class >= 0);
2612 //	Assert((Ship_info[Multi_ts_select_ship_class].desc != NULL) && strlen(Ship_info[Multi_ts_select_ship_class].desc));
2613 	if (Ship_info[Multi_ts_select_ship_class].desc != NULL)
2614 	{
2615 
2616 		// strip out newlines
2617 		memset(ship_desc,0,1000);
2618 		strcpy_s(ship_desc,Ship_info[Multi_ts_select_ship_class].desc);
2619 		token = strtok(ship_desc,"\n");
2620 		if(token != NULL){
2621 			strcpy_s(Multi_ts_ship_info_text,token);
2622 			while(token != NULL){
2623 				token = strtok(NULL,"\n");
2624 				if(token != NULL){
2625 					strcat_s(Multi_ts_ship_info_text," ");
2626 					strcat_s(Multi_ts_ship_info_text,token);
2627 				}
2628 			}
2629 		}
2630 
2631 		if(Multi_ts_ship_info_text[0] != '\0'){
2632 			// split the string into multiple lines
2633 			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);
2634 
2635 			// copy the split up lines into the text lines array
2636 			for (int idx = 0;idx<n_lines;idx++ ) {
2637 				Assert(n_chars[idx] < MULTI_TS_SHIP_INFO_MAX_LINE_LEN);
2638 				strncpy(Multi_ts_ship_info_lines[idx], p_str[idx], n_chars[idx]);
2639 				Multi_ts_ship_info_lines[idx][n_chars[idx]] = 0;
2640 				drop_leading_white_space(Multi_ts_ship_info_lines[idx]);
2641 			}
2642 
2643 			// get the line count
2644 			Multi_ts_ship_info_line_count = n_lines;
2645 		} else {
2646 			// set the line count to
2647 			Multi_ts_ship_info_line_count = 0;
2648 		}
2649 	}
2650 }
2651 
2652 // handle all details when the commit button is pressed (including possibly reporting errors/popups)
multi_ts_commit_pressed()2653 void multi_ts_commit_pressed()
2654 {
2655 	// if my team's slots are still not "locked", we cannot commit unless we're the only player in the game
2656 	if(!Multi_ts_team[Net_player->p_info.team].multi_players_locked){
2657 		if(multi_num_players() != 1){
2658 			popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK, XSTR("Players have not yet been assigned to their ships",751));
2659 			return;
2660 		} else {
2661 			Multi_ts_team[Net_player->p_info.team].multi_players_locked = 1;
2662 		}
2663 	}
2664 
2665 	// check to see if its not ok for this player to commit
2666 	switch(multi_ts_ok_to_commit()){
2667 	// yes, it _is_ ok to commit
2668 	case 0:
2669 		extern void commit_pressed();
2670 		commit_pressed();
2671 		break;
2672 
2673 	// player has not assigned all necessary ships
2674 	case 1:
2675 		gamesnd_play_iface(SND_GENERAL_FAIL);
2676 		popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK, XSTR("You have not yet assigned all necessary ships",752));
2677 		break;
2678 
2679 	// there are ships without primary weapons
2680 	case 2:
2681 		gamesnd_play_iface(SND_GENERAL_FAIL);
2682 		popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK, XSTR("There are ships without primary weapons!",753));
2683 		break;
2684 
2685 	// there are ships without secondary weapons
2686 	case 3:
2687 		gamesnd_play_iface(SND_GENERAL_FAIL);
2688 		popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,POPUP_OK, XSTR("There are ships without secondary weapons!",754));
2689 		break;
2690 	}
2691 }
2692 
2693 // is it ok for this player to commit
multi_ts_ok_to_commit()2694 int multi_ts_ok_to_commit()
2695 {
2696 	int idx,s_idx;
2697 	int primary_ok,secondary_ok;
2698 
2699 	// if this player is an observer, he can always commit
2700 	if(Net_player->flags & NETINFO_FLAG_OBSERVER){
2701 		return 0;
2702 	}
2703 
2704 	for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2705 		// if this is a player slot this player can modify and it is empty, then he cannot continue
2706 		// implies there is never an object in this slot
2707 		if((Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2708 			// implies player can't touch this slot anyway
2709 			!multi_ts_disabled_slot(idx) &&
2710 			// implies that there should be a player ship here but there isn't
2711 			((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)) ){
2712 			return 1;
2713 		}
2714 
2715 		// 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
2716 		if( (Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx] != -1) &&
2717 			((Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER) ||
2718 			 (Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP)) &&
2719 			 !multi_ts_disabled_slot(idx)){
2720 
2721 			primary_ok = 0;
2722 			secondary_ok = 0;
2723 			// go through all weapons in the list
2724 			for(s_idx=0;s_idx<MAX_SHIP_WEAPONS;s_idx++){
2725 				// if this slot has a weapon with a greater than 0 count, check
2726 				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)){
2727 					switch(Weapon_info[Wss_slots_teams[Net_player->p_info.team][idx].wep[s_idx]].subtype){
2728 					case WP_LASER:
2729 						primary_ok = 1;
2730 						break;
2731 
2732 					case WP_MISSILE:
2733 						secondary_ok = 1;
2734 						break;
2735 
2736 					default :
2737 						Int3();
2738 					}
2739 				}
2740 
2741 				// if we've got both primary and secondary weapons
2742 				if(primary_ok && secondary_ok){
2743 					break;
2744 				}
2745 			}
2746 
2747 			// if the ship doesn't have primary weapons
2748 			if (!primary_ok && !(The_mission.ai_profile->flags & AIPF_MULTI_ALLOW_EMPTY_PRIMARIES)) {
2749 				return 2;
2750 			}
2751 
2752 			// if the ship doesn't have secondary weapons
2753 			if (!secondary_ok && !(The_mission.ai_profile->flags & AIPF_MULTI_ALLOW_EMPTY_SECONDARIES)) {
2754 				return 3;
2755 			}
2756 		}
2757 	}
2758 
2759 	return 0;
2760 }
2761 
2762 // check to see that no illegal ship settings have occurred
multi_ts_check_errors()2763 void multi_ts_check_errors()
2764 {
2765 	/*
2766 	int idx;
2767 	ship *shipp;
2768 
2769 	for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
2770 		if(Multi_ts_team[0].multi_ts_objnum[idx] == -1){
2771 			continue;
2772 		}
2773 
2774 		shipp = &Ships[Objects[Multi_ts_team[0].multi_ts_objnum[idx]].instance];
2775 		Assert((shipp->weapons.current_primary_bank != -1) && (shipp->weapons.current_secondary_bank != -1));
2776 	}
2777 	*/
2778 }
2779 
2780 
2781 // ------------------------------------------------------------------------------------------------------
2782 // TEAM SELECT PACKET HANDLERS
2783 //
2784 
2785 // send a player slot position update
send_pslot_update_packet(int team,int code,int sound)2786 void send_pslot_update_packet(int team,int code,int sound)
2787 {
2788 	ubyte data[MAX_PACKET_SIZE],stop,val;
2789 	short s_sound;
2790 	int idx;
2791 	int packet_size = 0;
2792 	int i_tmp;
2793 
2794 	// build the header and add the data
2795 	BUILD_HEADER(SLOT_UPDATE);
2796 
2797 	// add the opcode
2798 	val = (ubyte)code;
2799 	ADD_DATA(val);
2800 
2801 	// add the team
2802 	val = (ubyte)team;
2803 	ADD_DATA(val);
2804 
2805 	// add the sound to play
2806 	s_sound = (short)sound;
2807 	ADD_SHORT(s_sound);
2808 
2809 	// add data based upon the packet code
2810 	switch(code){
2811 	case TS_CODE_LOCK_TEAM:
2812 		// don't have to do anything
2813 		break;
2814 	case TS_CODE_PLAYER_UPDATE:
2815 		// only the host should ever be doing this
2816 		Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
2817 
2818 		// add individual slot data
2819 		for(idx=0;idx<MAX_WSS_SLOTS;idx++){
2820 			if(Multi_ts_team[team].multi_ts_flag[idx] != MULTI_TS_FLAG_NONE){
2821 				// add a stop byte
2822 				stop = 0x0;
2823 				ADD_DATA(stop);
2824 
2825 				// add the slot #
2826 				val = (ubyte)idx;
2827 				ADD_DATA(val);
2828 
2829 				// add the ship class
2830 				val = (ubyte)Wss_slots_teams[team][idx].ship_class;
2831 				ADD_DATA(val);
2832 
2833 				// add the objnum we're working with
2834 				i_tmp = Multi_ts_team[team].multi_ts_objnum[idx];
2835 				ADD_INT(i_tmp);
2836 
2837 				// add a byte indicating if a player is here or not
2838 				if(Multi_ts_team[team].multi_ts_player[idx] == NULL){
2839 					val = 0;
2840 				} else {
2841 					val = 1;
2842 				}
2843 				ADD_DATA(val);
2844 
2845 				// if there's a player, add his address
2846 				if(val){
2847 					ADD_SHORT(Multi_ts_team[team].multi_ts_player[idx]->player_id);
2848 
2849 					// should also update his p_info settings locally
2850 					Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_class = Wss_slots_teams[team][idx].ship_class;
2851 					Multi_ts_team[team].multi_ts_player[idx]->p_info.ship_index = idx;
2852 				}
2853 
2854 				// 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)
2855 				if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_COULD_BE_PLAYER){
2856 					val = 2;
2857 				} else if(Objects[Multi_ts_team[team].multi_ts_objnum[idx]].flags & OF_PLAYER_SHIP){
2858 					val = 1;
2859 				} else {
2860 					val = 0;
2861 				}
2862 				ADD_DATA(val);
2863 			}
2864 		}
2865 		// add a final stop byte
2866 		val = 0xff;
2867 		ADD_DATA(val);
2868 		break;
2869 	default :
2870 		Int3();
2871 		break;
2872 	}
2873 
2874 	// send the packet to the standalone
2875 	if(Net_player->flags & NETINFO_FLAG_AM_MASTER) {
2876 		multi_io_send_to_all_reliable(data, packet_size);
2877 	} else {
2878 		multi_io_send_reliable(Net_player, data, packet_size);
2879 	}
2880 }
2881 
2882 // process a player slot position update
process_pslot_update_packet(ubyte * data,header * hinfo)2883 void process_pslot_update_packet(ubyte *data, header *hinfo)
2884 {
2885 	int offset = HEADER_LENGTH;
2886 	int my_index;
2887 	int player_index,idx,team,code,objnum;
2888 	short sound;
2889 	short player_id;
2890 	ubyte stop,val,slot_num,ship_class;
2891 
2892 	my_index = Net_player->p_info.ship_index;
2893 
2894 	// if we're the standalone, then we should be routing this data to all the other clients
2895 	player_index = -1;
2896 	if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2897 		// fill in the address information of where this came from
2898 		player_index = find_player_id(hinfo->id);
2899 		Assert(player_index != -1);
2900 	}
2901 
2902 	// get the opcode
2903 	GET_DATA(val);
2904 	code = (int)val;
2905 
2906 	// get the team
2907 	GET_DATA(val);
2908 	team = (int)val;
2909 
2910 	// get the sound to play
2911 	GET_SHORT(sound);
2912 
2913 	// process the different opcodes
2914 	switch(code){
2915 	case TS_CODE_LOCK_TEAM:
2916 		// lock the team
2917 		Multi_ts_team[team].multi_players_locked = 1;
2918 
2919 		// if this was my team, sync stuff up
2920 		if((team == Net_player->p_info.team) && !(Game_mode & GM_STANDALONE_SERVER)){
2921 			multi_ts_set_status_bar_mode(1);
2922 			multi_ts_sync_interface();
2923 			ss_recalc_multiplayer_slots();
2924 		}
2925 
2926 		// if this is the standalone server, we need to re-route the packet here and there
2927 		if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2928 			// in team vs team mode, only a team captain should ever be sending this
2929 			if(Netgame.type_flags & NG_TYPE_TEAM){
2930 				Assert(Net_players[player_index].flags & NETINFO_FLAG_TEAM_CAPTAIN);
2931 			}
2932 			// in any other mode, it better be coming from the game host
2933 			else {
2934 				Assert(Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST);
2935 			}
2936 
2937 			// re-route to all other players
2938 			for(idx=0;idx<MAX_PLAYERS;idx++){
2939 				if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
2940 					multi_io_send_reliable(&Net_players[idx], data, offset);
2941 				}
2942 			}
2943 		}
2944 		break;
2945 	case TS_CODE_PLAYER_UPDATE:
2946 		// get the first stop byte
2947 		GET_DATA(stop);
2948 		while(stop != 0xff){
2949 			// get the slot #
2950 			GET_DATA(slot_num);
2951 
2952 			// get the ship class
2953 			GET_DATA(ship_class);
2954 
2955 			// get the objnum
2956 			GET_INT(objnum);
2957 
2958 			// flag indicating if a player is in this slot
2959 			GET_DATA(val);
2960 			if(val){
2961 				// look the player up
2962 				GET_SHORT(player_id);
2963 				player_index = find_player_id(player_id);
2964 
2965 				// if we couldn't find him
2966 				if(player_index == -1){
2967 					nprintf(("Network","Couldn't find player for pslot update!\n"));
2968 					Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
2969 				}
2970 				// if we found him, assign him to this ship
2971 				else {
2972 					Net_players[player_index].p_info.ship_class = (int)ship_class;
2973 					Net_players[player_index].p_info.ship_index = (int)slot_num;
2974 					multi_assign_player_ship(player_index,&Objects[objnum],(int)ship_class);
2975 
2976 					// ui stuff
2977 					Multi_ts_team[team].multi_ts_player[slot_num] = &Net_players[player_index];
2978 
2979 					// if this was me and my ship index changed, update the weapon select screen
2980 					if(my_index != Net_player->p_info.ship_index){
2981 						wl_reset_selected_slot();
2982 
2983 						my_index = Net_player->p_info.ship_index;
2984 					}
2985 				}
2986 			} else {
2987 				Multi_ts_team[team].multi_ts_player[slot_num] = NULL;
2988 			}
2989 
2990 			// get the ship flag byte
2991 			GET_DATA(val);
2992 			Objects[objnum].flags &= ~(OF_PLAYER_SHIP | OF_COULD_BE_PLAYER);
2993 			switch(val){
2994 			case 1 :
2995 				Objects[objnum].flags |= OF_PLAYER_SHIP;
2996 				break;
2997 			case 2 :
2998 				obj_set_flags( &Objects[objnum], Objects[objnum].flags | OF_COULD_BE_PLAYER );
2999 				break;
3000 			}
3001 
3002 			// get the next stop byte
3003 			GET_DATA(stop);
3004 		}
3005 		// if we have a sound we're supposed to play
3006 		if((sound != -1) && !(Game_mode & GM_STANDALONE_SERVER) && (gameseq_get_state() == GS_STATE_TEAM_SELECT)){
3007 			gamesnd_play_iface(sound);
3008 		}
3009 
3010 		// if i'm the standalone server, I should rebroadcast this packet
3011 		if(Game_mode & GM_STANDALONE_SERVER){
3012 			for(idx=0;idx<MAX_PLAYERS;idx++){
3013 				if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_HOST(Net_players[idx]) && (Net_player != &Net_players[idx])){
3014 					multi_io_send_reliable(&Net_players[idx], data, offset);
3015 				}
3016 			}
3017 		}
3018 		break;
3019 	}
3020 	PACKET_SET_SIZE();
3021 
3022 	// recalculate stuff
3023 	if(!(Game_mode & GM_STANDALONE_SERVER)){
3024 		ss_recalc_multiplayer_slots();
3025 	}
3026 }
3027