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