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