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