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