diff --git a/data/scripts/mp/gametypes/_clientids.gsc b/data/scripts/mp/gametypes/_clientids.gsc deleted file mode 100644 index 0c2f5f36..00000000 Binary files a/data/scripts/mp/gametypes/_clientids.gsc and /dev/null differ diff --git a/data/scripts/mp/gametypes/_clientids.gsc_raw b/data/scripts/mp/gametypes/_clientids.gsc_raw deleted file mode 100644 index 1e8ac023..00000000 --- a/data/scripts/mp/gametypes/_clientids.gsc_raw +++ /dev/null @@ -1,33 +0,0 @@ -#using scripts\codescripts\struct; - -#using scripts\shared\callbacks_shared; -#using scripts\shared\system_shared; - -#insert scripts\shared\shared.gsh; - -#namespace clientids; - -REGISTER_SYSTEM( "clientids", &__init__, undefined ) - -function __init__() -{ - callback::on_start_gametype( &init ); - callback::on_connect( &on_player_connect ); -} - -function init() -{ - level.clientid = 0; - wait 0.5; - level.allow_teamchange = "1"; -} - -function on_player_connect() -{ - self.clientid = matchRecordNewPlayer( self ); - if ( !isdefined( self.clientid ) || self.clientid == -1 ) - { - self.clientid = level.clientid; - level.clientid++; - } -} \ No newline at end of file diff --git a/data/scripts/mp/gametypes/_serversettings.gsc b/data/scripts/mp/gametypes/_serversettings.gsc new file mode 100644 index 00000000..cd63bd0b Binary files /dev/null and b/data/scripts/mp/gametypes/_serversettings.gsc differ diff --git a/data/scripts/mp/gametypes/_serversettings.gsc_raw b/data/scripts/mp/gametypes/_serversettings.gsc_raw new file mode 100644 index 00000000..02669e86 --- /dev/null +++ b/data/scripts/mp/gametypes/_serversettings.gsc_raw @@ -0,0 +1,196 @@ +#using scripts\codescripts\struct; + +#using scripts\shared\callbacks_shared; +#using scripts\shared\system_shared; + +#insert scripts\shared\shared.gsh; + +#namespace serversettings; + +REGISTER_SYSTEM( "serversettings", &__init__, undefined ) + +function __init__() +{ + callback::on_start_gametype( &init ); +} + +function init() +{ + level.hostname = GetDvarString( "sv_hostname"); + if(level.hostname == "") + level.hostname = "CoDHost"; + SetDvar("sv_hostname", level.hostname); + SetDvar("ui_hostname", level.hostname); + + level.motd = GetDvarString( "scr_motd" ); + if(level.motd == "") + level.motd = ""; + SetDvar("scr_motd", level.motd); + SetDvar("ui_motd", level.motd); + + level.allowvote = GetDvarString( "g_allowvote"); + if(level.allowvote == "") + level.allowvote = "1"; + SetDvar("g_allowvote", level.allowvote); + SetDvar("ui_allowvote", level.allowvote); + + level.allow_teamchange = "1"; + SetDvar("ui_allow_teamchange", level.allow_teamchange); + + + level.friendlyfire = GetGametypeSetting( "friendlyfiretype" ); + + SetDvar("ui_friendlyfire", level.friendlyfire); + + if(GetDvarString( "scr_mapsize") == "") + SetDvar("scr_mapsize", "64"); + else if(GetDvarfloat( "scr_mapsize") >= 64) + SetDvar("scr_mapsize", "64"); + else if(GetDvarfloat( "scr_mapsize") >= 32) + SetDvar("scr_mapsize", "32"); + else if(GetDvarfloat( "scr_mapsize") >= 16) + SetDvar("scr_mapsize", "16"); + else + SetDvar("scr_mapsize", "8"); + level.mapsize = GetDvarfloat( "scr_mapsize"); + + constrain_gametype(GetDvarString( "g_gametype")); + constrain_map_size(level.mapsize); + + for(;;) + { + update(); + wait 5; + } +} + +function update() +{ + sv_hostname = GetDvarString( "sv_hostname"); + if(level.hostname != sv_hostname) + { + level.hostname = sv_hostname; + SetDvar("ui_hostname", level.hostname); + } + + scr_motd = GetDvarString( "scr_motd"); + if(level.motd != scr_motd) + { + level.motd = scr_motd; + SetDvar("ui_motd", level.motd); + } + + g_allowvote = GetDvarString( "g_allowvote"); + if(level.allowvote != g_allowvote) + { + level.allowvote = g_allowvote; + SetDvar("ui_allowvote", level.allowvote); + } + + scr_friendlyfire = GetGametypeSetting( "friendlyfiretype" ); + if(level.friendlyfire != scr_friendlyfire) + { + level.friendlyfire = scr_friendlyfire; + SetDvar("ui_friendlyfire", level.friendlyfire); + } +} + +function constrain_gametype(gametype) +{ + entities = getentarray(); + for(i = 0; i < entities.size; i++) + { + entity = entities[i]; + + if(gametype == "dm") + { + if(isdefined(entity.script_gametype_dm) && entity.script_gametype_dm != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "tdm") + { + if(isdefined(entity.script_gametype_tdm) && entity.script_gametype_tdm != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "ctf") + { + if(isdefined(entity.script_gametype_ctf) && entity.script_gametype_ctf != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "hq") + { + if(isdefined(entity.script_gametype_hq) && entity.script_gametype_hq != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "sd") + { + if(isdefined(entity.script_gametype_sd) && entity.script_gametype_sd != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + else if(gametype == "koth") + { + if(isdefined(entity.script_gametype_koth) && entity.script_gametype_koth != "1") + { + //iprintln("DELETED(GameType): ", entity.classname); + entity delete(); + } + } + } +} + +function constrain_map_size(mapsize) +{ + entities = getentarray(); + for(i = 0; i < entities.size; i++) + { + entity = entities[i]; + + if(int(mapsize) == 8) + { + if(isdefined(entity.script_mapsize_08) && entity.script_mapsize_08 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 16) + { + if(isdefined(entity.script_mapsize_16) && entity.script_mapsize_16 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 32) + { + if(isdefined(entity.script_mapsize_32) && entity.script_mapsize_32 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + else if(int(mapsize) == 64) + { + if(isdefined(entity.script_mapsize_64) && entity.script_mapsize_64 != "1") + { + //iprintln("DELETED(MapSize): ", entity.classname); + entity delete(); + } + } + } +} \ No newline at end of file diff --git a/data/scripts/mp/teams/_teams.gsc b/data/scripts/mp/teams/_teams.gsc new file mode 100644 index 00000000..bb53019a Binary files /dev/null and b/data/scripts/mp/teams/_teams.gsc differ diff --git a/data/scripts/mp/teams/_teams.gsc_raw b/data/scripts/mp/teams/_teams.gsc_raw new file mode 100644 index 00000000..1260a17b --- /dev/null +++ b/data/scripts/mp/teams/_teams.gsc_raw @@ -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 ); + } +} +