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