
                       ==== AutoTeamBalance README ====



# Installation:

    Drop the AutoTeamBalance.u file and the AutoTeamBalance.int file in your UT
    server's System folder.  Optionally edit and drop AutoTeamBalance.ini also.

    Then do one of the following:

      * Add the following line to your server's UnrealTournament.ini, under the
        [Engine.GameEngine] section:

          ServerActors=AutoTeamBalance.AutoTeamBalance

      OR

      * Tell your server to use AutoTeamBalance as a mutator (for example,
        using WebAdmin, or on the startup command).

    Don't worry, if you manged to do both of the above, AutoTeamBalance should
    detect that it is running twice, and recover gracefully.

    [Special note for SoNY_scarface: do not add it as a ServerPackage; there
    is no need, and it will only cause "Version mismatch" errors for your
    players if you upgrade to a newer version.]

    You may also wish to increase your server's NetWait to 10 or 20 seconds.
    (This value can be found in the [Botpack.DeathMatchPlus] section.)
    Initial teambalance is more effective if all the players are on the server
    when the game starts.  Players who join after game-start (e.g. because they
    were downloading the map) cannot be balanced so well.

    You should also ensure your server waits at least 10 seconds after the end
    of each game, before switching map, otherwise AutoTeamBalance will not
    have time to update the stats.  I think this is the RestartWait variable.

    I think, if your server has any bots, you should ensure that bBalanceTeams
    is set in your UnrealTournament.ini.  Since AutoTeamBalance does not affect
    the team placement of bots when they join, or when a player switches teams,
    this method should be enabled.  (AutoTeamBalance *will* change bots to
    different teams during *mid-game* balancing, if bBalanceBots is set.)



# What does it do?

AutoTeamBalance keeps a record of the skills of players on your server, and
uses the information to balance the teams at the beginning of each game. In
theory this should make games closer and fairer, or at the very least, better
than just randomly picked teams.

It actually performs team balancing with three different algorithms:

    1) At the beginning of the game (or when forced by a semi-admin), all
       players are balanced in a 1-2-2-2... pickup style
       [ForceFullTeamsRebalance].

    2) When a new player joins mid-game, he is assigned to the smaller team,
       or if both teams are the same size, the weaker team [ModifyLogin].

    3) When a player or admin requests [MidGameTeamBalance], either the
       1-player-switch or 2-player-switch rebalance algorithm will be called,
       depending on whether one team has more players or not.  This will
       attempt to make the strengths of the two teams as close as possible.

Usually one or two "!teams" rebalances should be sufficient to even the teams
if players have left the server mid-game.  But in unbalance emergencies,
semi-admins may also force a ForceFullTeamsRebalance mid-game, as in event 1,
but in this case players holding flags may get switched too!

AutoTeamBalance updates player stats shortly after the end of the game.  It can
record each player's average (normalised) score per 15 minutes, but the current
default setting is to award players with a score between 0 and 100, depending
on their position on the overall scoreboard.  Players who leave before or
immediately after the game ends will not have their stats updated.



# Commands available to players:

    Say "!teams" or "teams" to request MidGameTeamBalance.
    (Can be disabled by setting bLetPlayersRebalance to False in the config.)

    Say "!red" or "!blue" to get auto-switched to that team.

    Say "!spec" or "!play" to switch between spectator and player.

    Type "mutate strengths" in the console, to see the strengths of current
    players on the server.



The Administrator and semi-admins can type the following commands in the
console.  (You may wish to change the admin password in the config file, so
that semi-admins need not know the full server admin pass.  You can also empty
the password entirely, so that any player who knows the commands can be a
semi-admin, without having to type the password every time, but this may be
subject to abuse.)

    mutate help

        Displays a quick reminder of all these commands.

    mutate teams [password]

        Will switch one player to the other team, or will swap two players.
        The same as saying "teams" when bLetPlayersRebalance is set in the
        config.  Refuses to balance again for MinSecondsBeforeRebalance.

    mutate forceteams [password]

        The same as the teambalance which occurs at the beginning of the game.
        May switch a lot of players, including players holding the flag!

    mutate tored <player_name> [password]

        Moves the player to the Red team.  Here, and below, <player_name> need
        only be a part of the player's nick.

    mutate toblue <player_name> [password]

        Moves the player to the Blue team.

    mutate switch <player_name> <other_player_name> [password]

        Swaps the two players (easier and neater than using tored then toblue).

    mutate warn <player_name> <warning_message> [password]

        Flashes the warning message on the player's screen, and shakes his/her
        view.  (You may like to try it on yourself first.)

    mutate kick <player_name> <reason_message> [password]

        Flashes the message on the player's screen, then kicks him/her from the
        server.

    mutate kickban <player_name> <reason_message> [password]

        Flashes the message on the player's screen, then kicks and bans him/her
        from the server.



The following commands are only available to the Server Admin when he is logged
in:

    mutate saveconfig

        Updates the stats and saves everthing to the config file.  Note: if the
        game ends after this then the this time period passed will be counted
        again!

    mutate grantadmin <player_name>

        You can let a trusted player fiddle with your server, without having to
        give him the admin pass.

    mutate get <package> <var_name>

        Will display the gameengine's current value of the config variable.

    mutate set <package> <var_name> <new_value>

        Will change, and then display, the gameengine's current value of the
        config variable.  This is just a little friendlier than admin set,
        because you get feedback on your change.

    mutate getprop <var_name>
    mutate setprop <var_name> <new_value>
    mutate console <command>

        Experimental commands; use at your own risk



The default config should be fine for most servers.  But you may wish to tweak
one or two values to your needs.  For example, bWarnMidGameUnbalance is
disabled by default because you might find it too annoying - you may want to
try enabling it.  Here's an explanation of all the config variables:

  bBroadcastStuff=True                      - Whether or not to broadcast information to players at game start, game end, and when rebalancing mid-game.
  bBroadcastCookies=False                   - When enabled, at the end of the game, every player's strength change will be broadcast, represented as earning or losing cookies.  For debugging, or for fun.
  bFlashCookies=False                       - When enabled, each player will see his number of cookies at the start of the game, and how many he gained or lost at the end of the game.  For debugging, or for fun.
  bDebugLogging=False                       - Enable this only if you need to debug AutoTeamBalance.
  bLetPlayersRebalance=True                 - Allows players to fix teams mid-game by typing "teams" or "!teams".
  bForceEvenTeams=True                      - Automatically switches a player when one team has 2 players more than the other team.
  bWarnMidGameUnbalance=False               - Warns players if teams become uneven mid-game.
  bFlashOnWarning=True                      - The warning will flash across the HUD, instead of appearing in the chat area
  bShakeOnWarning=False                     - The warning will shake the screens of players on the stronger team
  bBuzzOnWarning=False                      - The warning will make the sound of buzzing flies for players on the stronger team
  bAllowSemiAdminKick=True                  - You can prevent semi-admins from kicking players by switching this off.
  bAllowSemiAdminForceTravel=True           - You can prevent semi-admins from forcing a server move by switching this off.
  bBalanceBots=False                        - Whether or not to balance bots as if they were humans (recommended off, since it might create 2v0 if bots are as strong as humans).
  bRankBots=False                           - Whether or not to record strengths for the bots (just for curiosity really).
  MinSecondsBeforeRebalance=20              - Prevents players from spamming "!teams"; should be at least 1, to avoid a bug with multiple calls to MutatorTeamMessage().
  SemiAdminPass=defaults_to_admin_pass      - Set this if you want semi-admins to use a different pass from the server admin pass.
  bAutoBalanceTeamsForCTF=True
  bAutoBalanceTeamsForTDM=True              - You can select which game-modes will be balanced, and which will not.
  bAutoBalanceTeamsForAS=True
  bAutoBalanceTeamsForOtherTeamGames=True
  bUpdatePlayerStatsForCTF=True             - BUG TODO:  Argh!  Won't this update scores from BT games too?!
  bUpdatePlayerStatsForTDM=True             - If you are normalising scores, then updating stats for TDM should be ok.  But if you are not normalising scores, then the different bonuses in CTF will make stats from the different gametypes incompatible.  (Basically TDMers will get lower strengths because they never get the bonus points from caps/covers/etc.)  So in this case you are recommended only to build stats for your server's most popular gametype.  Actually, now that we are using ScoringMethod 3, stats can be safely updated for all gametypes.
  bUpdatePlayerStatsForAS=True              - Now that the default scoring method is method 3, the huge AS bonuses are not a problem when updating player strengths.
  bUpdatePlayerStatsForOtherTeamGames=True  - This will record stats from JailBreak games, for example.
  bUpdatePlayerStatsForNonTeamGames=True    - DM scores are a good indication of a player's strength, even though it's not a team-game
  bLogExtraStats=False                      - records some extra player stats to the logfile at game-end, in case you are interested
  MaxHoursWhenCopyingOldRecord=4.0          - when a player changes nick or IP, his hours_played with the new nick or ip will be reduced to this, just in case it was a false-match, to minimise inaccurate stats for the new player
  HoursBeforeRecyclingStrength=6.0         - once a player has played for this long, his older scores start to fade away in favour of his more recent scores (to follow the strengths of players who get better or worse over time)
  MinHumansForStats=4                       - It's probably not healthy to update stats for 1v1 games, scores can be a little extreme
  ScoringMethod=2                           - How do we update the player's stats?  0=score, 1=frags, 2=average_frags_and_score, 3=0-100_ordered_ranking.  For CTF/TDM I recommend methods 0 or 2.  For Assault I recommend methods 2 or 3.
  bNormaliseScores=True                     - Normalises scores so that the average score for every game is 50, or whatever specified.  This is useful if scores from different games can be very different.  E.g. small spammy games get higher scores than large 2v2 games, and CTF has bonuses which you don't get in TDM.  Disadvantage: if strong and weak players play at different times on the server, they will get similar strengths, until they actually meet each other.  Disable normalisation if your server has similar scores at the end of every game.  This does not affect ScoringMethod 3, which is itself a kind of normalisation.
  bRelativeNormalisation=True               - During normalisation, the target average will be relative to the current strengths of players in the game.  So if you played against strong players, the strength you gain/lose will reflect this.
  bScalePlayerScoreToFullTime=True          - Should be kept True to ensure that scores are comparable when some players have joined the game late.  Players strength records are still only updated relative to the time they spent playing.
  NormalisedStrength=50                     - This need not be changed.  When using bNormaliseScores, it will simply affect the size of the numbers recorded in the database.
  UnknownStrength=45                        - New players are assumed to have strength 50 (Should be the same as NormalisedStrength, or if bNormaliseScores=False, it should be the average endgame-score-per-20-minute-game of new players on your server.  Only used for a new players during their first game; forgotten immediately afterwards.
  BotStrength=10                            - Maybe 20 or 30 is better, if you disable normalisation, or your bots are strong.  Of course this depends what difficulty the bots are set to on your server, and how effective they are on the maps you play, relative to the humans.
  FlagStrength=20                           - Affects the strength of each team, according to how many caps they have made.  If it's 3:0, the leading team will get an extra 3*FlagStrength = 60 points of strength.  This is used for balancing teams mid-game.
  StrengthThreshold=100                     - If bWarnMidGameUnbalance=True and team strength difference is greater than this, and the stronger team has more players, then all players are warned of team inbalance.  (Some threshold was needed, otherwise any player which switched to the smaller team would just make it look unbalanced the other way, causing never-ending team-unbalance warning!  In theory this might still happen with players of highly different strengths, in which case increase the threshold, or disable bWarnMidGameUnbalance)
  WinningTeamBonus=0                        - Maybe you scored low, but played good teamplay, so your team won, and you deserve higher strength for that.  Recommended values: 0/5/10.
  bClanWar=False                            - For clan wars; on player login or game start, moves players to the appropriate team by clan tag.
  clanTag=XOL                               - Clan tag of red team (all other players are sent to blue).
  bUseOnlyInGameScoresForRebalance=False    - Mid-game balancing usually looks up player records to see their strengths.  If you feel this causes lag on the server when a new player joins or during mid-game rebalancing, or you only want to balance using current game scores anyway (ignoring player records), then set this to True.
  bLogFakenickers=False                     - Write to log any players who had a previous record with a different nick or IP.
  bBroadcastFakenickers=False               - Broadcast to game any players who had a previous record with a different nick or IP.
  bSeparateStatsByGamemode=False            - Builds separate stats for different gametypes and different mutators.  Only use this if your server has a *few* different modes, and they require significantly different skills.  The number of records in your database will be multiplied by the number of different modes your server has.



# Known bugs:

  Well it hasn't been tested on BT games.  If the average score ends up below
  0, and score normalisation is enabled, then probably the players who died
  most will be given the highest strengths!  I recommend setting
  bNormaliseScores=False on BT servers.

  The mid-game teambalance warning can sometimes be a bit over-sensitive, e.g.
  in 2v1 situations.  If this happens too much, disable bWarnMidGameUnbalance,
  or increase the StrengthThreshold.

  I never got around to recording a player's last_time_played, which might be
  interesting info for admins, and also useful for recycling old player records
  when the database becomes full.



# Feedback:

  Please direct your feedback to the UnrealAdmin thread:
  http://www.unrealadmin.org/forums/showthread.php?t=23777

  If I get run over by a bus, I hope other coders can meet your requests for
  improvements there.



# Thanks to:

  XOL's Sourcerer, for the original mod which worked great on XOL, the
  initial code that got me started on UnrealScript, and feedback on earliest
  versions.
  iDeFiX, for holding my hand through my initial coding.
  Rork and _tAiger for testing.
  The author of TeamBallancer, because I lifted a tiny bit of his code.
  Adrian and Matt for some useful info in the Adwvaad thread.
  Debian GNU/Linux package maintainers, otherwise dammit I wouldn't have an OS
  to code on!
  And last but not least, my mum, for unleashing me upon you all.



Good luck and have fun, F0X|nogginBasher aka (-:SMo:-)c00ki3Mnstr.

