/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "network/multi_team.h" #include "globalincs/linklist.h" #include "iff_defs/iff_defs.h" #include "network/multi.h" #include "network/multi_endgame.h" #include "network/multi_pmsg.h" #include "network/multimsgs.h" #include "network/multiutil.h" #include "object/object.h" #include "playerman/player.h" #include "ship/ship.h" #include "stats/scoring.h" // ------------------------------------------------------------------------------------ // MULTIPLAYER TEAMPLAY DEFINES/VARS // // packet codes #define MT_CODE_TEAM_UPDATE 0 // send a full team update on a player-per-player basis #define MT_CODE_TEAM_REQUEST 1 // a request sent to the host to be be on a given team //XSTR:OFF // score for teams for this mission int Multi_team_score[MAX_TVT_TEAMS]; // ------------------------------------------------------------------------------------ // MULTIPLAYER TEAMPLAY FORWARD DECLARATIONS // // process a request to change a team void multi_team_process_team_change_request(net_player *pl,net_player *who_from,int team); // send a packet to the host requesting to change my team void multi_team_send_team_request(net_player *pl,int team); // have the netgame host assign default teams void multi_team_host_assign_default_teams(); // check to make sure all teams have a proper captain. void multi_team_sync_captains(); // process a team update packet, return bytes processed int multi_team_process_team_update(ubyte *data); // ------------------------------------------------------------------------------------ // MULTIPLAYER TEAMPLAY FUNCTIONS // // call before level load (pre-sync) void multi_team_level_init() { // score for teams 0 and 1 for this mission for (int i = 0; i < MAX_TVT_TEAMS; i++) Multi_team_score[i] = 0; } // call to determine who won the sw match, -1 == tie, 0 == team 0, 1 == team 1 int multi_team_winner() { int i, num_equal = 0, winner=-1, highest = -1; // determine highest score for (i = 0; i < Num_teams; i++) { if (Multi_team_score[i] > highest) { highest = Multi_team_score[i]; winner = i; } } // see if there are any ties for (i = 0; i < Num_teams; i++) { if (Multi_team_score[i] == highest) num_equal++; } // tie situation? if (num_equal > 1) return -1; return winner; } // call to add score to a team void multi_team_maybe_add_score(int points, int team) { // if we're not in multiplayer mode if(!(Game_mode & GM_MULTIPLAYER)){ return; } // if not squad war if(!(Netgame.type_flags & NG_TYPE_TEAM)){ return; } // if i'm not the server of the game, bail here if(!MULTIPLAYER_MASTER){ return; } // add team score Multi_team_score[team] += (int)(points * scoring_get_scale_factor()); nprintf(("Network", "TVT : adding %d points to team %d (total == %d)\n", points, team, Multi_team_score[team])); } // reset all players and assign them to default teams void multi_team_reset() { int idx; nprintf(("Network","MULTI TEAM : resetting\n")); // unset everyone's captaincy and locked flags for(idx=0;idxflags & NETINFO_FLAG_AM_MASTER){ // divvy up the teams here multi_team_host_assign_default_teams(); } } // set the captaincy status of this player void multi_team_set_captain(net_player *pl,int set) { // only the host should ever get here! Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); // set the player flags as being a captain and notify everyone else of this if(set){ nprintf(("Network","MULTI TEAM : Server setting player %s team %d captain\n",pl->m_player->callsign,pl->p_info.team)); pl->flags |= NETINFO_FLAG_TEAM_CAPTAIN; } else { nprintf(("Network","MULTI TEAM : Server unsetting player %s as team %d captain\n",pl->m_player->callsign,pl->p_info.team)); pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); } } // 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) void multi_team_set_team(net_player *pl,int team) { // if i'm the server of the game, do it now if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ nprintf(("Network","MULTI TEAM : Server/Host setting player %s to team %d and locking\n",pl->m_player->callsign,team)); pl->p_info.team = team; if(Net_player->flags & NETINFO_FLAG_GAME_HOST){ pl->flags |= NETINFO_FLAG_TEAM_LOCKED; } pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); // check to see if the resulting team rosters need a captain multi_team_sync_captains(); } else { nprintf(("Network","MULTI TEAM : Sending team change request to server\n")); multi_team_send_team_request(pl,team); } // verify that we have valid team stuff multi_team_verify(); } // process a request to change a team void multi_team_process_team_change_request(net_player *pl,net_player *who_from,int team) { // if this player has already been locked, don't do anything if((pl->flags & NETINFO_FLAG_TEAM_LOCKED) && !(who_from->flags & NETINFO_FLAG_GAME_HOST)){ nprintf(("Network","MULTI TEAM : Server ignoring team change request because player is locked\n")); return; } // otherwise set the team for the player and send an update nprintf(("Network","MULTI TEAM : Server changing player %s to team %d from client request\n",pl->m_player->callsign,team)); pl->p_info.team = team; pl->flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); // if this came from the host, lock the player down if(who_from->flags & NETINFO_FLAG_GAME_HOST){ pl->flags |= NETINFO_FLAG_TEAM_LOCKED; } // check to see if the resulting team rosters need a captain multi_team_sync_captains(); // send a team update multi_team_send_update(); // verify that we have valid team stuff multi_team_verify(); } // have the netgame host assign default teams void multi_team_host_assign_default_teams() { int player_count,idx; int team0_count; // first determine how many players there are in the game player_count = 0; for(idx=0;idx 0){ 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_LOCKED); Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); team0_count--; } idx++; } // assign the remaining players to team 1 while(idx < MAX_PLAYERS){ 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_LOCKED); Net_players[idx].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); } idx++; } // sync captains up multi_team_sync_captains(); // send a full update to all players multi_team_send_update(); // verify that we have valid team stuff multi_team_verify(); } // check to see if the team this player on needs a captain and assign him if so void multi_team_sync_captains() { int idx; int team0_cap,team1_cap; // if I'm not the server, bail if(!MULTIPLAYER_MASTER){ return; } // determine if any team now needs a captain team0_cap = 0; team1_cap = 0; for(idx=0;idx 0)) ? 1 : 0; team1_count = ((team1_count <= 4) && (team1_count > 0)) ? 1 : 0; return ((team0_captains == 1) && (team1_captains == 1) && team0_count && team1_count) ? 1 : 0; } // handle a player drop void multi_team_handle_drop() { int idx; int team0_cap, team1_cap; // if I'm not the server, bail if(!MULTIPLAYER_MASTER){ return; } // if we're not in a team vs team situation, we don't care if(!(Netgame.type_flags & NG_TYPE_TEAM)){ return; } // is either team at 0 players, ingame? if(Game_mode & GM_IN_MISSION){ int team0_count, team1_count; multi_team_get_player_counts(&team0_count, &team1_count); if(team0_count <= 0){ multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_TEAM0_EMPTY); return; } if(team1_count <= 0){ multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_TEAM1_EMPTY); return; } } // check to see if a team captain has left the game team0_cap = 0; team1_cap = 0; for(idx=0;idxflags & NETINFO_FLAG_OBSERVER){ return; } // only the host should ever do this Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){ return; } // count the # of players on each time team0_count = 0; team1_count = 0; for(idx=0;idxflags &= ~(NETINFO_FLAG_TEAM_LOCKED); // send a team update multi_team_send_update(); // verify that we have valid team stuff multi_team_verify(); } // set all ships in the mission to be marked as the proper team (TEAM_HOSTILE, TEAM_FRIENLY) void multi_team_mark_all_ships() { ship_obj *moveup; // look through all ships in the mission moveup = GET_FIRST(&Ship_obj_list); while(moveup!=END_OF_LIST(&Ship_obj_list)){ multi_team_mark_ship(&Ships[Objects[moveup->objnum].instance]); moveup = GET_NEXT(moveup); } // verify that we have valid team stuff multi_team_verify(); } // set the proper team for the passed in ship void multi_team_mark_ship(ship *sp) { int i; // look through TVT wings... each wing corresponds to a team for (i = 0; i < MAX_TVT_WINGS; i++) { if (sp->wingnum == TVT_wings[i]) sp->team = i; } // verify that we have valid team stuff multi_team_verify(); } // host locks all players into their teams void multi_team_host_lock_all() { int idx; // lock all players down for(idx=0;idx", (1275+i)), Multi_team_score[i]); } // Karajorma - If the SCP has added more teams we won't have a XSTR to handle it. So just output in english for now else { sprintf(report, "Team %d had %d points>", (i+1), Multi_team_score[i]); } SEND_AND_DISPLAY(report); } // display winner switch(multi_team_winner()) { case -1: SEND_AND_DISPLAY(XSTR("", 1277)); break; case 0: SEND_AND_DISPLAY(XSTR("", 1278)); break; case 1: SEND_AND_DISPLAY(XSTR("", 1279)); break; default: // need to come up with a new message here Int3(); break; } // a little header SEND_AND_DISPLAY("----****"); } // ------------------------------------------------------------------------------------ // MULTIPLAYER TEAMPLAY PACKET HANDLERS // // process an incoming team update packet void multi_team_process_packet(unsigned char *data, header *hinfo) { ubyte code; int player_index; int offset = HEADER_LENGTH; // find out who is sending this data player_index = find_player_id(hinfo->id); // get the packet opcode GET_DATA(code); // take action absed upon the opcode switch((int)code){ // a request to set the team for a player case MT_CODE_TEAM_REQUEST: ushort player_id; int req_index,req_team; Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); // get the packet data GET_USHORT(player_id); GET_INT(req_team); // if i'm the host of the game, process here req_index = find_player_id(player_id); if( (req_index == -1) || (player_index == -1) ){ nprintf(("Network","Could not find player to process team change request !\n")); } else { multi_team_process_team_change_request(&Net_players[req_index],&Net_players[player_index],req_team); } break; // a full team update case MT_CODE_TEAM_UPDATE: offset += multi_team_process_team_update(data+offset); break; } PACKET_SET_SIZE(); // verify that we have valid team stuff multi_team_verify(); } // send a packet to the host requesting to change my team void multi_team_send_team_request(net_player *pl, int team) { ubyte data[MAX_PACKET_SIZE],code; int packet_size = 0; // build the header and add the opcode BUILD_HEADER(TEAM_UPDATE); code = MT_CODE_TEAM_REQUEST; ADD_DATA(code); // add the address of the guy we want to change ADD_SHORT(pl->player_id); // add the team I want to be on ADD_INT(team); // send to the server of the game (will be routed to host if in a standalone situation) multi_io_send_reliable(Net_player, data, packet_size); } // send a full update on a player-per-player basis (should call this to update all players after other relevant function calls) void multi_team_send_update() { ubyte data[MAX_PACKET_SIZE],val,stop; int idx; int packet_size = 0; // if I'm not the server, bail if(!MULTIPLAYER_MASTER){ return; } // first, verify that we have valid settings multi_team_verify(); // build the header and add the opcode BUILD_HEADER(TEAM_UPDATE); val = MT_CODE_TEAM_UPDATE; ADD_DATA(val); // add the info for all players; for(idx=0;idxflags & NETINFO_FLAG_AM_MASTER){ multi_io_send_to_all_reliable(data, packet_size); } else { multi_io_send_reliable(Net_player, data, packet_size); } } // process a team update packet, return bytes processed int multi_team_process_team_update(ubyte *data) { ubyte stop,flags; short player_id; int player_index; int offset = 0; // if I'm the server, bail Assert(!MULTIPLAYER_MASTER); // process all players GET_DATA(stop); while(stop != 0xff){ // get the net address and flags for the guy GET_SHORT(player_id); GET_DATA(flags); // do a player lookup if(!MULTIPLAYER_MASTER){ player_index = find_player_id(player_id); if(player_index != -1){ // set his team correctly if(flags & (1<<0)){ Net_players[player_index].p_info.team = 1; } else { Net_players[player_index].p_info.team = 0; } // set his captaincy flag correctly Net_players[player_index].flags &= ~(NETINFO_FLAG_TEAM_CAPTAIN); if(flags & (1<<1)){ Net_players[player_index].flags |= NETINFO_FLAG_TEAM_CAPTAIN; } } } // get the next stop byte GET_DATA(stop); } // verify that we have valid team stuff multi_team_verify(); // return bytes processed return offset; } // verify that we have valid team stuff void multi_team_verify() { #ifndef NDEBUG int team0_count,team0_cap; int team1_count,team1_cap; int idx; // determine how many players we have on team 0 and if they have a captain team0_count = 0; team0_cap = 0; for(idx=0;idx 0){ // make sure it also has a captain Assert(team0_cap > 0); // make sure it only has 1 captain Assert(team0_cap == 1); } // determine how many players we have on team 1 and if they have a captain team1_count = 0; team1_cap = 0; for(idx=0;idx 0){ // make sure it also has a captain Assert(team1_cap > 0); // make sure it only has 1 captain Assert(team1_cap == 1); } #endif }