Add autobalance support.
Setting scr_teambalance 1 will now autobalance teams after 60 seconds.
This commit is contained in:
parent
9322bba426
commit
66bea25aaa
BIN
data/scripts/mp/teams/_teams.gsc
Normal file
BIN
data/scripts/mp/teams/_teams.gsc
Normal file
Binary file not shown.
670
data/scripts/mp/teams/_teams.gsc_raw
Normal file
670
data/scripts/mp/teams/_teams.gsc_raw
Normal file
@ -0,0 +1,670 @@
|
||||
#using scripts\codescripts\struct;
|
||||
|
||||
#using scripts\shared\callbacks_shared;
|
||||
#using scripts\shared\persistence_shared;
|
||||
#using scripts\shared\system_shared;
|
||||
#using scripts\shared\util_shared;
|
||||
|
||||
#insert scripts\shared\shared.gsh;
|
||||
|
||||
#using scripts\mp\gametypes\_globallogic_ui;
|
||||
#using scripts\mp\gametypes\_spectating;
|
||||
|
||||
#using scripts\mp\_util;
|
||||
|
||||
#precache( "material", "mpflag_spectator" );
|
||||
#precache( "string", "MP_AUTOBALANCE_NOW" );
|
||||
|
||||
#namespace teams;
|
||||
|
||||
REGISTER_SYSTEM( "teams", &__init__, undefined )
|
||||
|
||||
function __init__()
|
||||
{
|
||||
callback::on_start_gametype( &init );
|
||||
|
||||
level.getEnemyTeam = &getEnemyTeam;
|
||||
level.use_team_based_logic_for_locking_on = true;
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
game["strings"]["autobalance"] = &"MP_AUTOBALANCE_NOW";
|
||||
|
||||
if(GetDvarString( "scr_teambalance") == "")
|
||||
SetDvar("scr_teambalance", "0");
|
||||
level.teambalance = GetDvarint( "scr_teambalance");
|
||||
level.teambalancetimer = 0;
|
||||
|
||||
if(GetDvarString( "scr_timeplayedcap") == "")
|
||||
SetDvar("scr_timeplayedcap", "1800");
|
||||
level.timeplayedcap = int(GetDvarint( "scr_timeplayedcap"));
|
||||
|
||||
level.freeplayers = [];
|
||||
|
||||
if( level.teamBased )
|
||||
{
|
||||
level.alliesplayers = [];
|
||||
level.axisplayers = [];
|
||||
|
||||
callback::on_connect( &on_player_connect );
|
||||
callback::on_joined_team( &on_joined_team );
|
||||
callback::on_joined_spectate( &on_joined_spectators );
|
||||
level thread update_team_balance();
|
||||
|
||||
wait .15;
|
||||
|
||||
level thread update_player_times();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
callback::on_connect( &on_free_player_connect );
|
||||
|
||||
wait .15;
|
||||
|
||||
level thread update_player_times();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function on_player_connect()
|
||||
{
|
||||
self thread track_played_time();
|
||||
}
|
||||
|
||||
function on_free_player_connect()
|
||||
{
|
||||
self thread track_free_played_time();
|
||||
}
|
||||
|
||||
function on_joined_team()
|
||||
{
|
||||
/#println( "joined team: " + self.pers["team"] );#/
|
||||
self update_time();
|
||||
}
|
||||
|
||||
function on_joined_spectators()
|
||||
{
|
||||
self.pers["teamTime"] = undefined;
|
||||
}
|
||||
|
||||
function track_played_time()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
if ( !isdefined( self.pers["totalTimePlayed"] ) )
|
||||
{
|
||||
self.pers["totalTimePlayed"] = 0;
|
||||
}
|
||||
|
||||
foreach ( team in level.teams )
|
||||
{
|
||||
self.timePlayed[team] = 0;
|
||||
}
|
||||
self.timePlayed["free"] = 0;
|
||||
self.timePlayed["other"] = 0;
|
||||
self.timePlayed["alive"] = 0;
|
||||
|
||||
// dont reset time played in War when going into final fight, this is used for calculating match bonus
|
||||
if ( !isdefined( self.timePlayed["total"] ) || !( (level.gameType == "twar") && (0 < game["roundsplayed"]) && (0 < self.timeplayed["total"]) ) )
|
||||
self.timePlayed["total"] = 0;
|
||||
|
||||
while ( level.inPrematchPeriod )
|
||||
WAIT_SERVER_FRAME;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( game["state"] == "playing" )
|
||||
{
|
||||
if ( isdefined( level.teams[self.sessionteam] ) )
|
||||
{
|
||||
self.timePlayed[self.sessionteam]++;
|
||||
self.timePlayed["total"]++;
|
||||
|
||||
if ( level.mpCustomMatch )
|
||||
{
|
||||
self.pers["sbtimeplayed"] = self.timeplayed["total"];
|
||||
self.sbtimeplayed = self.pers["sbtimeplayed"];
|
||||
}
|
||||
|
||||
if ( IsAlive( self ) )
|
||||
self.timePlayed["alive"]++;
|
||||
}
|
||||
else if ( self.sessionteam == "spectator" )
|
||||
{
|
||||
self.timePlayed["other"]++;
|
||||
}
|
||||
}
|
||||
|
||||
wait ( 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update_player_times()
|
||||
{
|
||||
const minWait = 10.0;
|
||||
const step = 1.0;
|
||||
varWait = minWait;
|
||||
|
||||
nextToUpdate = 0;
|
||||
for ( ;; )
|
||||
{
|
||||
varWait = varWait - step;
|
||||
nextToUpdate++;
|
||||
|
||||
if ( nextToUpdate >= level.players.size )
|
||||
{
|
||||
nextToUpdate = 0;
|
||||
|
||||
if ( varWait > 0 )
|
||||
{
|
||||
wait ( varWait );
|
||||
}
|
||||
|
||||
varWait = minWait;
|
||||
}
|
||||
|
||||
if ( isdefined( level.players[nextToUpdate] ) )
|
||||
{
|
||||
level.players[nextToUpdate] update_played_time();
|
||||
level.players[nextToUpdate] persistence::check_contract_expirations();
|
||||
}
|
||||
|
||||
wait ( step );
|
||||
}
|
||||
}
|
||||
|
||||
function update_played_time()
|
||||
{
|
||||
pixbeginevent("updatePlayedTime");
|
||||
|
||||
if ( level.rankedMatch || level.leagueMatch )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
if ( self.timePlayed[team] )
|
||||
{
|
||||
if ( level.teambased )
|
||||
{
|
||||
self AddPlayerStat( "time_played_"+team, int( min( self.timePlayed[team], level.timeplayedcap ) ) );
|
||||
}
|
||||
|
||||
self AddPlayerStatWithGameType( "time_played_total", int( min( self.timePlayed[team], level.timeplayedcap ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( self.timePlayed["other"] )
|
||||
{
|
||||
self AddPlayerStat( "time_played_other", int( min( self.timePlayed["other"], level.timeplayedcap ) ) );
|
||||
self AddPlayerStatWithGameType( "time_played_total", int( min( self.timePlayed["other"], level.timeplayedcap ) ) );
|
||||
}
|
||||
|
||||
if ( self.timePlayed["alive"] )
|
||||
{
|
||||
timeAlive = int( min( self.timePlayed["alive"], level.timeplayedcap ) );
|
||||
self persistence::increment_contract_times( timeAlive );
|
||||
self AddPlayerStat( "time_played_alive", timeAlive );
|
||||
}
|
||||
}
|
||||
|
||||
if ( level.onlineGame )
|
||||
{
|
||||
timeAlive = int( min( self.timePlayed["alive"], level.timeplayedcap ) );
|
||||
self.pers["time_played_alive"] += timeAlive;
|
||||
}
|
||||
|
||||
pixendevent();
|
||||
|
||||
if ( game["state"] == "postgame" )
|
||||
return;
|
||||
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
self.timePlayed[team] = 0;
|
||||
}
|
||||
self.timePlayed["other"] = 0;
|
||||
self.timePlayed["alive"] = 0;
|
||||
}
|
||||
|
||||
|
||||
function update_time()
|
||||
{
|
||||
if ( game["state"] != "playing" )
|
||||
return;
|
||||
|
||||
self.pers["teamTime"] = getTime();
|
||||
}
|
||||
|
||||
function update_balance_dvar()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
teambalance = GetDvarint( "scr_teambalance");
|
||||
if(level.teambalance != teambalance)
|
||||
level.teambalance = GetDvarint( "scr_teambalance");
|
||||
|
||||
timeplayedcap = GetDvarint( "scr_timeplayedcap");
|
||||
if(level.timeplayedcap != timeplayedcap)
|
||||
level.timeplayedcap = int(GetDvarint( "scr_timeplayedcap"));
|
||||
|
||||
wait 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update_team_balance()
|
||||
{
|
||||
level thread update_balance_dvar();
|
||||
|
||||
wait .15;
|
||||
|
||||
if ( level.teamBalance && util::isRoundBased() && level.numlives )
|
||||
{
|
||||
if ( isDefined( game["BalanceTeamsNextRound"] ) )
|
||||
iPrintLnbold( &"MP_AUTOBALANCE_NEXT_ROUND" );
|
||||
|
||||
level waittill( "game_ended" );
|
||||
wait 1;
|
||||
|
||||
if ( isDefined( game["BalanceTeamsNextRound"] ) )
|
||||
{
|
||||
level balance_teams();
|
||||
game["BalanceTeamsNextRound"] = undefined;
|
||||
}
|
||||
else if ( !get_team_balance() )
|
||||
{
|
||||
game["BalanceTeamsNextRound"] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( level.teamBalance )
|
||||
{
|
||||
if ( !get_team_balance() )
|
||||
{
|
||||
iPrintLnBold( &"MP_AUTOBALANCE_SECONDS", 15 );
|
||||
wait 15.0;
|
||||
|
||||
if ( !get_team_balance() )
|
||||
level balance_teams();
|
||||
}
|
||||
|
||||
wait 59.0;
|
||||
}
|
||||
|
||||
wait 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get_team_balance()
|
||||
{
|
||||
level.team["allies"] = 0;
|
||||
level.team["axis"] = 0;
|
||||
|
||||
players = level.players;
|
||||
|
||||
for ( i = 0; i < players.size; i++ )
|
||||
{
|
||||
if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) )
|
||||
level.team["allies"]++;
|
||||
else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) )
|
||||
level.team["axis"]++;
|
||||
}
|
||||
|
||||
if ( ( level.team["allies"] > ( level.team["axis"] + level.teamBalance ) ) || ( level.team["axis"] > ( level.team["allies"] + level.teamBalance ) ) )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function balance_teams()
|
||||
{
|
||||
iPrintLnBold( game["strings"]["autobalance"] );
|
||||
//Create/Clear the team arrays
|
||||
AlliedPlayers = [];
|
||||
AxisPlayers = [];
|
||||
|
||||
// Populate the team arrays
|
||||
players = level.players;
|
||||
|
||||
for ( i = 0; i < players.size; i++ )
|
||||
{
|
||||
if ( !isdefined( players[i].pers["teamTime"] ) )
|
||||
continue;
|
||||
|
||||
if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) )
|
||||
AlliedPlayers[AlliedPlayers.size] = players[i];
|
||||
else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) )
|
||||
AxisPlayers[AxisPlayers.size] = players[i];
|
||||
}
|
||||
|
||||
MostRecent = undefined;
|
||||
|
||||
while ( ( AlliedPlayers.size > ( AxisPlayers.size + 1 ) ) || ( AxisPlayers.size > ( AlliedPlayers.size + 1 ) ) )
|
||||
{
|
||||
if ( AlliedPlayers.size > ( AxisPlayers.size + 1 ) )
|
||||
{
|
||||
// Move the player that's been on the team the shortest ammount of time (highest teamTime value)
|
||||
// Ignore players capturing or carrying objects
|
||||
for ( j = 0; j < AlliedPlayers.size; j++ )
|
||||
{
|
||||
|
||||
if ( !isdefined( MostRecent ) )
|
||||
MostRecent = AlliedPlayers[j];
|
||||
else if ( AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] )
|
||||
MostRecent = AlliedPlayers[j];
|
||||
}
|
||||
|
||||
if ( isdefined( MostRecent ) )
|
||||
MostRecent change( "axis" );
|
||||
else
|
||||
{
|
||||
// Move the player that's been on the team the shortest ammount of time
|
||||
for ( j = 0; j < AlliedPlayers.size; j++ )
|
||||
{
|
||||
if ( !isdefined( MostRecent ) )
|
||||
MostRecent = AlliedPlayers[j];
|
||||
else if ( AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] )
|
||||
MostRecent = AlliedPlayers[j];
|
||||
}
|
||||
|
||||
MostRecent change( "axis" );
|
||||
}
|
||||
}
|
||||
else if ( AxisPlayers.size > ( AlliedPlayers.size + 1 ) )
|
||||
{
|
||||
// Move the player that's been on the team the shortest ammount of time (highest teamTime value)
|
||||
// Ignore players capturing or carrying objects
|
||||
for ( j = 0; j < AxisPlayers.size; j++ )
|
||||
{
|
||||
|
||||
if ( !isdefined( MostRecent ) )
|
||||
MostRecent = AxisPlayers[j];
|
||||
else if ( AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] )
|
||||
MostRecent = AxisPlayers[j];
|
||||
}
|
||||
|
||||
if ( isdefined( MostRecent ) )
|
||||
MostRecent change( "allies" );
|
||||
else
|
||||
{
|
||||
// Move the player that's been on the team the shortest ammount of time
|
||||
for ( j = 0; j < AxisPlayers.size; j++ )
|
||||
{
|
||||
if ( !isdefined( MostRecent ) )
|
||||
MostRecent = AxisPlayers[j];
|
||||
else if ( AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"] )
|
||||
MostRecent = AxisPlayers[j];
|
||||
}
|
||||
|
||||
MostRecent change( "allies" );
|
||||
}
|
||||
}
|
||||
|
||||
MostRecent = undefined;
|
||||
AlliedPlayers = [];
|
||||
AxisPlayers = [];
|
||||
|
||||
players = level.players;
|
||||
|
||||
for ( i = 0; i < players.size; i++ )
|
||||
{
|
||||
if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "allies" ) )
|
||||
AlliedPlayers[AlliedPlayers.size] = players[i];
|
||||
else if ( ( isdefined( players[i].pers["team"] ) ) && ( players[i].pers["team"] == "axis" ) )
|
||||
AxisPlayers[AxisPlayers.size] = players[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function change( team )
|
||||
{
|
||||
if (self.sessionstate != "dead")
|
||||
{
|
||||
// Set a flag on the player to they aren't robbed points for dying - the callback will remove the flag
|
||||
self.switching_teams = true;
|
||||
self.switchedTeamsResetGadgets = true;
|
||||
self.joining_team = team;
|
||||
self.leaving_team = self.pers["team"];
|
||||
|
||||
// Suicide the player so they can't hit escape and fail the team balance
|
||||
self suicide();
|
||||
}
|
||||
|
||||
self.pers["team"] = team;
|
||||
self.team = team;
|
||||
self.pers["weapon"] = undefined;
|
||||
self.pers["spawnweapon"] = undefined;
|
||||
self.pers["savedmodel"] = undefined;
|
||||
self.pers["teamTime"] = undefined;
|
||||
self.sessionteam = self.pers["team"];
|
||||
|
||||
self globallogic_ui::updateObjectiveText();
|
||||
|
||||
// update spectator permissions immediately on change of team
|
||||
self spectating::set_permissions();
|
||||
|
||||
self SetClientScriptMainMenu( game[ "menu_start_menu" ] );
|
||||
self openMenu(game[ "menu_start_menu" ]);
|
||||
|
||||
self notify("end_respawn");
|
||||
}
|
||||
|
||||
function count_players()
|
||||
{
|
||||
players = level.players;
|
||||
|
||||
playerCounts = [];
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
playerCounts[team] = 0;
|
||||
}
|
||||
|
||||
foreach( player in level.players )
|
||||
{
|
||||
if( player == self )
|
||||
continue;
|
||||
|
||||
team = player.pers["team"];
|
||||
if( isdefined(team) && isdefined( level.teams[team] ) )
|
||||
playerCounts[team]++;
|
||||
}
|
||||
return playerCounts;
|
||||
}
|
||||
|
||||
|
||||
function track_free_played_time()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
self.timePlayed[team] = 0;
|
||||
}
|
||||
|
||||
self.timePlayed["other"] = 0;
|
||||
self.timePlayed["total"] = 0;
|
||||
self.timePlayed["alive"] = 0;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( game["state"] == "playing" )
|
||||
{
|
||||
team = self.pers["team"];
|
||||
if ( isdefined( team ) && isdefined( level.teams[team] ) && self.sessionteam != "spectator" )
|
||||
{
|
||||
self.timePlayed[team]++;
|
||||
self.timePlayed["total"]++;
|
||||
if ( IsAlive( self ) )
|
||||
self.timePlayed["alive"]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.timePlayed["other"]++;
|
||||
}
|
||||
}
|
||||
|
||||
wait ( 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
function set_player_model( team, weapon )
|
||||
{
|
||||
self DetachAll();
|
||||
self SetMoveSpeedScale( 1 );
|
||||
self SetSprintDuration( 4 );
|
||||
self SetSprintCooldown( 0 );
|
||||
}
|
||||
|
||||
function get_flag_model( teamRef )
|
||||
{
|
||||
assert(isdefined(game["flagmodels"]));
|
||||
assert(isdefined(game["flagmodels"][teamRef]));
|
||||
return ( game["flagmodels"][teamRef] );
|
||||
}
|
||||
|
||||
function get_flag_carry_model( teamRef )
|
||||
{
|
||||
assert(isdefined(game["carry_flagmodels"]));
|
||||
assert(isdefined(game["carry_flagmodels"][teamRef]));
|
||||
return ( game["carry_flagmodels"][teamRef] );
|
||||
}
|
||||
|
||||
function getTeamIndex( team )
|
||||
{
|
||||
if( !isdefined( team ) )
|
||||
{
|
||||
return TEAM_FREE;
|
||||
}
|
||||
|
||||
if( team == "free" )
|
||||
{
|
||||
return TEAM_FREE;
|
||||
}
|
||||
|
||||
if( team == "allies" )
|
||||
{
|
||||
return TEAM_ALLIES;
|
||||
}
|
||||
|
||||
if( team == "axis" )
|
||||
{
|
||||
return TEAM_AXIS;
|
||||
}
|
||||
|
||||
return TEAM_FREE;
|
||||
}
|
||||
|
||||
function getEnemyTeam( player_team )
|
||||
{
|
||||
foreach( team in level.teams )
|
||||
{
|
||||
if ( team == player_team )
|
||||
continue;
|
||||
|
||||
if ( team == "spectator" )
|
||||
continue;
|
||||
|
||||
return team;
|
||||
}
|
||||
|
||||
return util::getOtherTeam( player_team );
|
||||
}
|
||||
|
||||
function GetEnemyPlayers()
|
||||
{
|
||||
enemies = [];
|
||||
|
||||
foreach( player in level.players )
|
||||
{
|
||||
if( player.team == "spectator" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( level.teamBased && player.team != self.team ) || ( !level.teamBased && player != self ) )
|
||||
{
|
||||
ARRAY_ADD( enemies, player );
|
||||
}
|
||||
}
|
||||
|
||||
return enemies;
|
||||
}
|
||||
|
||||
function GetFriendlyPlayers()
|
||||
{
|
||||
friendlies = [];
|
||||
|
||||
foreach( player in level.players )
|
||||
{
|
||||
if( ( player.team == self.team ) && ( player != self ) )
|
||||
{
|
||||
ARRAY_ADD( friendlies, player );
|
||||
}
|
||||
}
|
||||
|
||||
return friendlies;
|
||||
}
|
||||
|
||||
function WaitUntilTeamChange( player, callback, arg, end_condition1, end_condition2, end_condition3 )
|
||||
{
|
||||
if( isdefined( end_condition1 ) )
|
||||
self endon( end_condition1 );
|
||||
if( isdefined( end_condition2 ) )
|
||||
self endon( end_condition2 );
|
||||
if( isdefined( end_condition3 ) )
|
||||
self endon( end_condition3 );
|
||||
|
||||
event = player util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
if( isdefined( callback ) )
|
||||
{
|
||||
self [[ callback ]]( arg, event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function WaitUntilTeamChangeSingleTon( player, singletonString, callback, arg, end_condition1, end_condition2, end_condition3 )
|
||||
{
|
||||
self notify( singletonString );
|
||||
self endon( singletonString );
|
||||
if( isdefined( end_condition1 ) )
|
||||
self endon( end_condition1 );
|
||||
if( isdefined( end_condition2 ) )
|
||||
self endon( end_condition2 );
|
||||
if( isdefined( end_condition3 ) )
|
||||
self endon( end_condition3 );
|
||||
|
||||
event = player util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
|
||||
|
||||
if( isdefined( callback ) )
|
||||
{
|
||||
self thread [[ callback ]]( arg, event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function HideToSameTeam()
|
||||
{
|
||||
if( level.teambased )
|
||||
{
|
||||
self SetVisibleToAllExceptTeam( self.team );
|
||||
}
|
||||
else
|
||||
{
|
||||
self SetVisibleToAll();
|
||||
self SetInvisibleToPlayer( self.owner );
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user