2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Network/multi_team.cpp $
16 * Revision 1.5 2005/10/02 09:30:10 taylor
17 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
19 * Revision 1.4 2004/06/11 01:45:13 tigital
20 * byte-swapping changes for bigendian systems
22 * Revision 1.3 2002/06/09 04:41:24 relnev
23 * added copyright header
25 * Revision 1.2 2002/05/07 03:16:47 theoddone33
26 * The Great Newline Fix
28 * Revision 1.1.1.1 2002/05/03 03:28:10 root
32 * 13 9/08/99 1:59p Dave
33 * Nailed the problem with assigning teams improperly in TvT. Basic
34 * problem was that clients were sending team update packets with bogus
35 * info that the server was willingly accepting, thereby blowing away his
38 * 12 8/22/99 1:55p Dave
39 * Cleaned up host/team-captain leaving code.
41 * 11 8/22/99 1:19p Dave
42 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
43 * which d3d cards are detected.
45 * 10 4/09/99 2:21p Dave
46 * Multiplayer beta stuff. CD checking.
48 * 9 3/10/99 6:50p Dave
49 * Changed the way we buffer packets for all clients. Optimized turret
50 * fired packets. Did some weapon firing optimizations.
52 * 8 3/09/99 6:24p Dave
53 * More work on object update revamping. Identified several sources of
54 * unnecessary bandwidth.
56 * 7 2/17/99 2:11p Dave
57 * First full run of squad war. All freespace and tracker side stuff
60 * 6 2/11/99 3:08p Dave
61 * PXO refresh button. Very preliminary squad war support.
63 * 5 11/19/98 8:03a Dave
64 * Full support for D3-style reliable sockets. Revamped packet lag/loss
65 * system, made it receiver side and at the lowest possible level.
67 * 4 11/17/98 11:12a Dave
68 * Removed player identification by address. Now assign explicit id #'s.
70 * 3 11/05/98 5:55p Dave
71 * Big pass at reducing #includes
73 * 2 10/07/98 10:53a Dave
76 * 1 10/07/98 10:50a Dave
78 * 18 6/13/98 3:19p Hoffoss
79 * NOX()ed out a bunch of strings that shouldn't be translated.
81 * 17 5/26/98 7:33p Dave
82 * Once extra check for TvT oktocommit. Tested against all cases.
84 * 16 5/22/98 9:35p Dave
85 * Put in channel based support for PXO. Put in "shutdown" button for
86 * standalone. UI tweaks for TvT
88 * 15 5/15/98 5:16p Dave
89 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
90 * status for team vs. team. Put in asserts to check for invalid team vs.
93 * 14 5/03/98 7:04p Dave
94 * Make team vs. team work mores smoothly with standalone. Change how host
95 * interacts with standalone for picking missions. Put in a time limit for
96 * ingame join ship select. Fix ingame join ship select screen for Vasudan
99 * 13 4/22/98 5:53p Dave
100 * Large reworking of endgame sequencing. Updated multi host options
101 * screen for new artwork. Put in checks for host or team captains leaving
104 * 12 4/15/98 5:03p Dave
105 * Put in a rough countdown to mission start on final sync screen. Fixed
106 * several team vs. team bugs on the ship/team select screen.
108 * 11 4/14/98 12:57a Dave
109 * Made weapon select screen show netplayer names above ships. Fixed pilot
110 * info popup to show the status of pilot images more correctly.
112 * 10 4/08/98 2:51p Dave
113 * Fixed pilot image xfer once again. Solidify team selection process in
114 * pre-briefing multiplayer.
116 * 9 4/04/98 4:22p Dave
117 * First rev of UDP reliable sockets is done. Seems to work well if not
120 * 8 4/03/98 1:03a Dave
121 * First pass at unreliable guaranteed delivery packets.
123 * 7 3/31/98 4:51p Dave
124 * Removed medals screen and multiplayer buttons from demo version. Put in
125 * new pilot popup screen. Make ships in mp team vs. team have proper team
126 * ids. Make mp respawns a permanent option saved in the player file.
128 * 6 3/15/98 4:17p Dave
129 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
130 * of network orientation matrices.
132 * 5 3/12/98 5:45p Dave
133 * Put in new observer HUD. Made it possible for observers to join at the
134 * beginning of a game and follow it around as an observer full-time.
136 * 4 3/10/98 4:26p Dave
137 * Second pass at furball mode. Fixed several team vs. team bugs.
139 * 3 3/09/98 5:54p Dave
140 * Fixed stats to take asteroid hits into account. Polished up UI stuff in
141 * team select. Finished up pilot info popup. Tracked down and fixed
144 * 2 3/03/98 8:55p Dave
145 * Finished pre-briefing team vs. team support.
147 * 1 3/03/98 5:09p Dave
152 #include "freespace.h"
153 #include "linklist.h"
154 #include "multimsgs.h"
155 #include "multiutil.h"
156 #include "multi_team.h"
157 #include "multi_endgame.h"
158 #include "multi_pmsg.h"
161 // ------------------------------------------------------------------------------------
162 // MULTIPLAYER TEAMPLAY DEFINES/VARS
166 #define MT_CODE_TEAM_UPDATE 0 // send a full team update on a player-per-player basis
167 #define MT_CODE_TEAM_REQUEST 1 // a request sent to the host to be be on a given team
171 const char *Multi_team0_names[4] = { // ships on team 0 (TEAM_FRIENDLY)
172 "alpha 1", "alpha 2", "alpha 3", "alpha 4"
174 const char *Multi_team1_names[4] = { // ships on team 1 (TEAM_HOSTILE)
175 "zeta 1", "zeta 2", "zeta 3", "zeta 4"
178 // score for teams 0 and 1 for this mission
179 int Multi_team0_score = 0;
180 int Multi_team1_score = 0;
183 // ------------------------------------------------------------------------------------
184 // MULTIPLAYER TEAMPLAY FORWARD DECLARATIONS
187 // process a request to change a team
188 void multi_team_process_team_change_request(net_player *pl,net_player *who_from,int team);
190 // send a packet to the host requesting to change my team
191 void multi_team_send_team_request(net_player *pl,int team);
193 // have the netgame host assign default teams
194 void multi_team_host_assign_default_teams();
196 // check to make sure all teams have a proper captain.
197 void multi_team_sync_captains();
199 // process a team update packet, return bytes processed
200 int multi_team_process_team_update(ubyte *data);
203 // ------------------------------------------------------------------------------------
204 // MULTIPLAYER TEAMPLAY FUNCTIONS
207 // call before level load (pre-sync)
208 void multi_team_level_init()
210 // score for teams 0 and 1 for this mission
211 Multi_team0_score = 0;
212 Multi_team1_score = 0;
215 // call to determine who won the sw match, -1 == tie, 0 == team 0, 1 == team 1
216 int multi_team_winner()
221 if(Multi_team0_score == Multi_team1_score){
226 if(Multi_team0_score > Multi_team1_score){
230 // team 1 must have won
234 // call to add score to a team
235 void multi_team_maybe_add_score(int points, int team)
237 // if we're not in multiplayer mode
238 if(!(Game_mode & GM_MULTIPLAYER)){
243 if(!(Netgame.type_flags & NG_TYPE_TEAM)){
247 // if i'm not the server of the game, bail here
248 if(!MULTIPLAYER_MASTER){
255 nprintf(("Network", "TVT : adding %d points to team 0 (total == %d)\n", points, points + Multi_team0_score));
256 Multi_team0_score += points;
260 nprintf(("Network", "TVT : adding %d points to team 1 (total == %d)\n", points, points + Multi_team1_score));
261 Multi_team1_score += points;
266 // reset all players and assign them to default teams
267 void multi_team_reset()
271 nprintf(("Network","MULTI TEAM : resetting\n"));
273 // unset everyone's captaincy and locked flags
274 for(idx=0;idx<MAX_PLAYERS;idx++){
275 if(MULTI_CONNECTED(Net_players[idx])){
276 Net_players[idx].p_info.team = 0;
277 Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_LOCKED | NETINFO_FLAG_TEAM_CAPTAIN);
281 // host should divvy up the teams, send a reset notice to all players and assign captains
282 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
283 // divvy up the teams here
284 multi_team_host_assign_default_teams();
288 // set the captaincy status of this player
289 void multi_team_set_captain(net_player *pl,int set)
291 // only the host should ever get here!
292 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
294 // set the player flags as being a captain and notify everyone else of this
296 nprintf(("Network","MULTI TEAM : Server setting player %s team %d captain\n",pl->player->callsign,pl->p_info.team));
297 pl->flags |= NETINFO_FLAG_TEAM_CAPTAIN;
299 nprintf(("Network","MULTI TEAM : Server unsetting player %s as team %d captain\n",pl->player->callsign,pl->p_info.team));
300 pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
304 // set the team of this given player (if called by the host, the player becomes locked, cnad only the host can modify him from thereon)
305 void multi_team_set_team(net_player *pl,int team)
307 // if i'm the server of the game, do it now
308 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
309 nprintf(("Network","MULTI TEAM : Server/Host setting player %s to team %d and locking\n",pl->player->callsign,team));
311 pl->p_info.team = team;
313 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
314 pl->flags |= NETINFO_FLAG_TEAM_LOCKED;
316 pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
318 // check to see if the resulting team rosters need a captain
319 multi_team_sync_captains();
321 nprintf(("Network","MULTI TEAM : Sending team change request to server\n"));
322 multi_team_send_team_request(pl,team);
325 // verify that we have valid team stuff
329 // process a request to change a team
330 void multi_team_process_team_change_request(net_player *pl,net_player *who_from,int team)
332 // if this player has already been locked, don't do anything
333 if((pl->flags & NETINFO_FLAG_TEAM_LOCKED) && !(who_from->flags & NETINFO_FLAG_GAME_HOST)){
334 nprintf(("Network","MULTI TEAM : Server ignoring team change request because player is locked\n"));
338 // otherwise set the team for the player and send an update
339 nprintf(("Network","MULTI TEAM : Server changing player %s to team %d from client request\n",pl->player->callsign,team));
340 pl->p_info.team = team;
341 pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
343 // if this came from the host, lock the player down
344 if(who_from->flags & NETINFO_FLAG_GAME_HOST){
345 pl->flags |= NETINFO_FLAG_TEAM_LOCKED;
348 // check to see if the resulting team rosters need a captain
349 multi_team_sync_captains();
351 // send a team update
352 multi_team_send_update();
354 // verify that we have valid team stuff
358 // have the netgame host assign default teams
359 void multi_team_host_assign_default_teams()
361 int player_count,idx;
364 // first determine how many players there are in the game
366 for(idx=0;idx<MAX_PLAYERS;idx++){
367 // count anyone except the standalone server (if applicable)
368 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
373 // determine how many players should be stuck on team 0
374 if(player_count < 2){
377 team0_count = player_count / 2;
380 // assign the players to team 0
382 while(team0_count > 0){
383 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
384 Net_players[idx].p_info.team = 0;
385 Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_LOCKED);
386 Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
393 // assign the remaining players to team 1
394 while(idx < MAX_PLAYERS){
395 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
396 Net_players[idx].p_info.team = 1;
397 Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_LOCKED);
398 Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
404 multi_team_sync_captains();
406 // send a full update to all players
407 multi_team_send_update();
409 // verify that we have valid team stuff
413 // check to see if the team this player on needs a captain and assign him if so
414 void multi_team_sync_captains()
417 int team0_cap,team1_cap;
419 // if I'm not the server, bail
420 if(!MULTIPLAYER_MASTER){
424 // determine if any team now needs a captain
427 for(idx=0;idx<MAX_PLAYERS;idx++){
428 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
429 switch(Net_players[idx].p_info.team){
440 // if team 0 needs a captain, get one
442 for(idx=0;idx<MAX_PLAYERS;idx++){
443 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.team == 0) && !(Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
444 multi_team_set_captain(&Net_players[idx],1);
450 // if team 1 needs a captain, get one
452 for(idx=0;idx<MAX_PLAYERS;idx++){
453 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].p_info.team == 1) && !(Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
454 multi_team_set_captain(&Net_players[idx],1);
461 // is it ok for the host to hit commit
462 int multi_team_ok_to_commit()
464 int team0_captains,team1_captains;
465 int team0_count,team1_count;
468 // verify that we have valid team stuff
471 // check to see if both teams have a captain
475 for(idx=0;idx<MAX_PLAYERS;idx++){
476 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
477 // if this is team 0's captain
478 if((Net_players[idx].p_info.team == 0) && (Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
480 } else if((Net_players[idx].p_info.team == 1) && (Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
486 // check to see if both teams has <= 4 players
487 multi_team_get_player_counts(&team0_count,&team1_count);
488 team0_count = ((team0_count <= 4) && (team0_count > 0)) ? 1 : 0;
489 team1_count = ((team1_count <= 4) && (team1_count > 0)) ? 1 : 0;
491 return ((team0_captains == 1) && (team1_captains == 1) && team0_count && team1_count) ? 1 : 0;
494 // handle a player drop
495 void multi_team_handle_drop()
498 int team0_cap, team1_cap;
500 // if I'm not the server, bail
501 if(!MULTIPLAYER_MASTER){
505 // if we're not in a team vs team situation, we don't care
506 if(!(Netgame.type_flags & NG_TYPE_TEAM)){
510 // is either team at 0 players, ingame?
511 if(Game_mode & GM_IN_MISSION){
512 int team0_count, team1_count;
513 multi_team_get_player_counts(&team0_count, &team1_count);
514 if(team0_count <= 0){
515 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_TEAM0_EMPTY);
518 if(team1_count <= 0){
519 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_TEAM1_EMPTY);
524 // check to see if a team captain has left the game
527 for(idx=0;idx<MAX_PLAYERS;idx++){
528 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN)){
529 switch(Net_players[idx].p_info.team){
540 // if we have lost a team captain and we're not in the forming state, abort the game
541 if((!team0_cap || !team1_cap) && (Netgame.game_state != NETGAME_STATE_FORMING)){
542 // if we're in-mission, just sync up captains
543 if(Game_mode & GM_IN_MISSION){
545 multi_team_sync_captains();
547 // send a team update
548 multi_team_send_update();
550 // find the player who is the new captain
551 int team_check = team0_cap ? 1 : 0;
552 for(idx=0; idx<MAX_PLAYERS; idx++){
553 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN) && (Net_players[idx].p_info.team == team_check)){
554 send_host_captain_change_packet(Net_players[idx].player_id, 1);
561 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CAPTAIN_LEFT);
563 // otherwise sync things up and be done with it.
565 // sync up team captains
566 multi_team_sync_captains();
568 // send a team update
569 multi_team_send_update();
571 // verify that we have valid team stuff
576 // handle a player join
577 void multi_team_handle_join(net_player *pl)
579 int team0_count,team1_count,idx,team_select;
581 // if we're not in a team vs team situation, we don't care
582 if(!(Netgame.type_flags & NG_TYPE_TEAM)){
586 // if the joining player is joining as an observer, don't put him on a team
587 if(pl->flags & NETINFO_FLAG_OBSERVER){
591 // only the host should ever do this
592 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
593 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
597 // count the # of players on each time
600 for(idx=0;idx<MAX_PLAYERS;idx++){
601 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
602 // player is on team 0
603 if(Net_players[idx].p_info.team == 0){
606 // player is on team 1
607 else if(Net_players[idx].p_info.team == 1){
610 // some other case - should never happen
617 // determine what team he should be on
618 if((team0_count == team1_count) || (team0_count < team1_count)){
624 // place him on the team, but don't lock him yet
625 multi_team_set_team(pl,team_select);
626 pl->flags &= ~(NETINFO_FLAG_TEAM_LOCKED);
628 // send a team update
629 multi_team_send_update();
631 // verify that we have valid team stuff
635 // set all ships in the mission to be marked as the proper team (TEAM_HOSTILE, TEAM_FRIENLY)
636 void multi_team_mark_all_ships()
640 // look through all ships in the mission
641 moveup = GET_FIRST(&Ship_obj_list);
642 while(moveup!=END_OF_LIST(&Ship_obj_list)){
643 multi_team_mark_ship(&Ships[Objects[moveup->objnum].instance]);
645 moveup = GET_NEXT(moveup);
648 // verify that we have valid team stuff
652 // set the proper team for the passed in ship
653 void multi_team_mark_ship(ship *sp)
661 // look through team 0
662 for(idx=0;idx<4;idx++){
663 if(!SDL_strcasecmp(sp->ship_name,Multi_team0_names[idx])){
669 // look through team 1 if necessary
671 for(idx=0;idx<4;idx++){
672 if(!SDL_strcasecmp(sp->ship_name,Multi_team1_names[idx])){
679 // if we found a team
682 sp->team = TEAM_FRIENDLY;
685 sp->team = TEAM_HOSTILE;
689 // verify that we have valid team stuff
693 // host locks all players into their teams
694 void multi_team_host_lock_all()
698 // lock all players down
699 for(idx=0;idx<MAX_PLAYERS;idx++){
700 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
701 Net_players[idx].flags |= NETINFO_FLAG_TEAM_LOCKED;
705 // verify that we have valid team stuff
709 // get the player counts for team 0 and team 1 (NULL values are valid)
710 void multi_team_get_player_counts(int *team0, int *team1)
714 // initialize the values
723 for(idx=0;idx<MAX_PLAYERS;idx++){
724 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
725 if((Net_players[idx].p_info.team == 0) && (team0 != NULL)){
727 } else if((Net_players[idx].p_info.team == 1) && (team1 != NULL)){
734 // report on the winner/loser of the game via chat text
735 #define SEND_AND_DISPLAY(mesg) do { send_game_chat_packet(Net_player, mesg, MULTI_MSG_ALL, NULL, NULL, 1); multi_display_chat_msg(mesg, 0, 0); } while(0);
736 void multi_team_report()
738 char report[400] = "";
741 SEND_AND_DISPLAY("----****");
744 SDL_snprintf(report, SDL_arraysize(report), XSTR("<Team 1 had %d points>", 1275), Multi_team0_score);
745 SEND_AND_DISPLAY(report);
746 SDL_snprintf(report, SDL_arraysize(report), XSTR("<Team 2 had %d points>", 1276), Multi_team1_score);
747 SEND_AND_DISPLAY(report);
750 switch(multi_team_winner()){
752 SEND_AND_DISPLAY(XSTR("<Match was a tie>", 1277));
756 SEND_AND_DISPLAY(XSTR("<Team 1 (green) is the winner>", 1278));
760 SEND_AND_DISPLAY(XSTR("<Team 2 (red) is the winner>", 1279));
764 SEND_AND_DISPLAY("----****");
768 // ------------------------------------------------------------------------------------
769 // MULTIPLAYER TEAMPLAY PACKET HANDLERS
772 // process an incoming team update packet
773 void multi_team_process_packet(unsigned char *data, header *hinfo)
777 int offset = HEADER_LENGTH;
779 // find out who is sending this data
780 player_index = find_player_id(hinfo->id);
782 // get the packet opcode
785 // take action absed upon the opcode
787 // a request to set the team for a player
788 case MT_CODE_TEAM_REQUEST:
790 int req_index,req_team;
792 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
794 // get the packet data
795 GET_USHORT(player_id);
798 // if i'm the host of the game, process here
799 req_index = find_player_id(player_id);
801 nprintf(("Network","Could not find player to process team change request !\n"));
803 multi_team_process_team_change_request(&Net_players[req_index],&Net_players[player_index],req_team);
807 // a full team update
808 case MT_CODE_TEAM_UPDATE:
809 offset += multi_team_process_team_update(data+offset);
815 // verify that we have valid team stuff
819 // send a packet to the host requesting to change my team
820 void multi_team_send_team_request(net_player *pl, int team)
822 ubyte data[MAX_PACKET_SIZE],code;
825 // build the header and add the opcode
826 BUILD_HEADER(TEAM_UPDATE);
827 code = MT_CODE_TEAM_REQUEST;
830 // add the address of the guy we want to change
831 ADD_SHORT(pl->player_id);
833 // add the team I want to be on
836 // send to the server of the game (will be routed to host if in a standalone situation)
837 multi_io_send_reliable(Net_player, data, packet_size);
840 // send a full update on a player-per-player basis (should call this to update all players after other relevant function calls)
841 void multi_team_send_update()
843 ubyte data[MAX_PACKET_SIZE],val,stop;
847 // if I'm not the server, bail
848 if(!MULTIPLAYER_MASTER){
852 // first, verify that we have valid settings
855 // build the header and add the opcode
856 BUILD_HEADER(TEAM_UPDATE);
857 val = MT_CODE_TEAM_UPDATE;
860 // add the info for all players;
861 for(idx=0;idx<MAX_PLAYERS;idx++){
862 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
868 ADD_SHORT(Net_players[idx].player_id);
870 // pack all his data into a byte
873 // set bit 0 if he's on team 1
874 if(Net_players[idx].p_info.team == 1){
878 // set bit 1 if he's a team captain
879 if(Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN){
886 // add the final stop byte
890 // if i'm the server, I should broadcast to this to all players, otherwise I should send it to the standalone
891 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
892 multi_io_send_to_all_reliable(data, packet_size);
894 multi_io_send_reliable(Net_player, data, packet_size);
898 // process a team update packet, return bytes processed
899 int multi_team_process_team_update(ubyte *data)
906 // if I'm the server, bail
907 SDL_assert(!MULTIPLAYER_MASTER);
909 // process all players
912 // get the net address and flags for the guy
913 GET_SHORT(player_id);
916 // do a player lookup
917 if(!MULTIPLAYER_MASTER){
918 player_index = find_player_id(player_id);
919 if(player_index != -1){
920 // set his team correctly
922 Net_players[player_index].p_info.team = 1;
924 Net_players[player_index].p_info.team = 0;
927 // set his captaincy flag correctly
928 Net_players[player_index].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN);
930 Net_players[player_index].flags |= NETINFO_FLAG_TEAM_CAPTAIN;
935 // get the next stop byte
939 // verify that we have valid team stuff
942 // return bytes processed
946 // verify that we have valid team stuff
947 void multi_team_verify()
950 int team0_count,team0_cap;
951 int team1_count,team1_cap;
954 // determine how many players we have on team 0 and if they have a captain
957 for(idx=0;idx<MAX_PLAYERS;idx++){
958 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
960 if(Net_players[idx].p_info.team == 0){
964 if(Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN){
970 // if the team has members
972 // make sure it also has a captain
973 SDL_assert(team0_cap > 0);
975 // make sure it only has 1 captain
976 SDL_assert(team0_cap == 1);
979 // determine how many players we have on team 1 and if they have a captain
982 for(idx=0;idx<MAX_PLAYERS;idx++){
983 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
985 if(Net_players[idx].p_info.team == 1){
989 if(Net_players[idx].flags & NETINFO_FLAG_TEAM_CAPTAIN){
995 // if the team has members
997 // make sure it also has a captain
998 SDL_assert(team1_cap > 0);
1000 // make sure it only has 1 captain
1001 SDL_assert(team1_cap == 1);