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