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