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