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