Beispiel #1
0
        public ActionResult ReportToAdminFromLobby(string id)
        {
            var     db = new ZkDataContext();
            int     idint;
            Account user = null;

            if (int.TryParse(id, out idint))
            {
                user = Account.AccountByLobbyID(db, idint);
            }
            if (user == null)
            {
                user = Account.AccountByName(db, id);
            }

            return(View("ReportToAdmin", user));
        }
Beispiel #2
0
        public ActionResult LobbyDetail(string id)
        {
            var     db = new ZkDataContext();
            int     idint;
            Account user = null;

            if (int.TryParse(id, out idint))
            {
                user = Account.AccountByLobbyID(db, idint);
            }
            if (user == null)
            {
                user = Account.AccountByName(db, id);
            }

            return(View("UserDetail", user));
        }
Beispiel #3
0
        Account UpdateUser(int lobbyID, string name, User user, string hashedPassword, ZkDataContext db = null)
        {
            Account acc = null;

            if (db == null)
            {
                db = new ZkDataContext();
            }

            acc = Account.AccountByLobbyID(db, lobbyID);
            if (acc == null)
            {
                acc = new Account();
                db.Accounts.InsertOnSubmit(acc);
            }

            acc.LobbyID = lobbyID;
            acc.Name    = name;
            if (!string.IsNullOrEmpty(hashedPassword))
            {
                acc.Password = hashedPassword;
            }
            acc.LastLogin = DateTime.UtcNow;

            if (user != null) // user was online, we can update his data
            {
                acc.IsBot = user.IsBot;
                acc.IsLobbyAdministrator = user.IsAdmin;
                acc.Country       = user.Country;
                acc.LobbyTimeRank = user.Rank;
            }

            db.SubmitAndMergeChanges();

            return(acc);
        }
Beispiel #4
0
        List <Faction> GetDefendingFactions(AttackOption target)
        {
            if (target.OwnerFactionID != null)
            {
                return new List <Faction> {
                           factions.Find(x => x.FactionID == target.OwnerFactionID)
                }
            }
            ;
            return(factions.Where(x => x != AttackingFaction).ToList());
        }

        void JoinPlanetAttack(int targetPlanetId, string userName)
        {
            AttackOption attackOption = AttackOptions.Find(x => x.PlanetID == targetPlanetId);

            if (attackOption != null)
            {
                User user;

                if (tas.ExistingUsers.TryGetValue(userName, out user))
                {
                    var     db      = new ZkDataContext();
                    Account account = Account.AccountByLobbyID(db, user.LobbyID);
                    if (account != null && account.FactionID == AttackingFaction.FactionID && account.CanPlayerPlanetWars())
                    {
                        // remove existing user from other options
                        foreach (AttackOption aop in AttackOptions)
                        {
                            aop.Attackers.RemoveAll(x => x == userName);
                        }

                        // add user to this option
                        if (attackOption.Attackers.Count < attackOption.TeamSize)
                        {
                            attackOption.Attackers.Add(user.Name);
                            tas.Say(TasClient.SayPlace.Channel, user.Faction, string.Format("{0} joins attack on {1}", userName, attackOption.Name), true);

                            if (attackOption.Attackers.Count == attackOption.TeamSize)
                            {
                                StartChallenge(attackOption);
                            }
                            else
                            {
                                UpdateLobby();
                            }
                        }
                    }
                }
            }
        }

        void JoinPlanetDefense(int targetPlanetID, string userName)
        {
            if (Challenge != null && Challenge.PlanetID == targetPlanetID && Challenge.Defenders.Count < Challenge.TeamSize)
            {
                User user;
                if (tas.ExistingUsers.TryGetValue(userName, out user))
                {
                    var     db      = new ZkDataContext();
                    Account account = Account.AccountByLobbyID(db, user.LobbyID);
                    if (account != null && GetDefendingFactions(Challenge).Any(y => y.FactionID == account.FactionID) && account.CanPlayerPlanetWars())
                    {
                        if (!Challenge.Defenders.Any(y => y == user.Name))
                        {
                            Challenge.Defenders.Add(user.Name);
                            tas.Say(TasClient.SayPlace.Channel, user.Faction, string.Format("{0} joins defense of {1}", userName, Challenge.Name), true);

                            if (Challenge.Defenders.Count == Challenge.TeamSize)
                            {
                                AcceptChallenge();
                            }
                            else
                            {
                                UpdateLobby();
                            }
                        }
                    }
                }
            }
        }

        void RecordPlanetwarsLoss(AttackOption option)
        {
            if (option.OwnerFactionID != null)
            {
                if (option.OwnerFactionID == missedDefenseFactionID)
                {
                    missedDefenseCount++;
                }
                else
                {
                    missedDefenseCount     = 0;
                    missedDefenseFactionID = option.OwnerFactionID.Value;
                }
            }


            var message = string.Format("{0} won because nobody tried to defend", AttackingFaction.Name);

            foreach (var fac in factions)
            {
                tas.Say(TasClient.SayPlace.Channel, fac.Shortcut, message, true);
            }


            var text = new StringBuilder();

            try
            {
                var           db        = new ZkDataContext();
                List <string> playerIds = option.Attackers.Select(x => x).Union(option.Defenders.Select(x => x)).ToList();


                PlanetWarsTurnHandler.EndTurn(option.Map, null, db, 0, db.Accounts.Where(x => playerIds.Contains(x.Name) && x.Faction != null).ToList(), text, null, db.Accounts.Where(x => option.Attackers.Contains(x.Name) && x.Faction != null).ToList());
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                text.Append(ex);
            }
        }

        void ResetAttackOptions()
        {
            AttackOptions.Clear();
            AttackerSideChangeTime = DateTime.UtcNow;
            Challenge     = null;
            ChallengeTime = null;

            using (var db = new ZkDataContext())
            {
                var gal      = db.Galaxies.First(x => x.IsDefault);
                int cnt      = 2;
                var attacker = db.Factions.Single(x => x.FactionID == AttackingFaction.FactionID);
                var planets  = gal.Planets.Where(x => x.OwnerFactionID != AttackingFaction.FactionID).OrderByDescending(x => x.PlanetFactions.Where(y => y.FactionID == AttackingFaction.FactionID).Sum(y => y.Dropships)).ThenByDescending(x => x.PlanetFactions.Where(y => y.FactionID == AttackingFaction.FactionID).Sum(y => y.Influence)).ToList();
                // list of planets by attacker's influence

                foreach (var planet in planets)
                {
                    if (planet.CanMatchMakerPlay(attacker))
                    {
                        // pick only those where you can actually attack atm
                        InternalAddOption(planet);
                        cnt--;
                    }
                    if (cnt == 0)
                    {
                        break;
                    }
                }

                if (!AttackOptions.Any(y => y.TeamSize == 2))
                {
                    var planet = planets.FirstOrDefault(x => x.TeamSize == 2 && x.CanMatchMakerPlay(attacker));
                    if (planet != null)
                    {
                        InternalAddOption(planet);
                    }
                }
            }

            UpdateLobby();

            tas.Say(TasClient.SayPlace.Channel, AttackingFaction.Shortcut, "It's your turn! Select a planet to attack", true);
        }

        void InternalAddOption(Planet planet)
        {
            AttackOptions.Add(new AttackOption
            {
                PlanetID       = planet.PlanetID,
                Map            = planet.Resource.InternalName,
                OwnerFactionID = planet.OwnerFactionID,
                Name           = planet.Name,
                TeamSize       = planet.TeamSize,
            });
        }

        void SaveStateToDb()
        {
            var    db  = new ZkDataContext();
            Galaxy gal = db.Galaxies.First(x => x.IsDefault);

            gal.MatchMakerState = JsonConvert.SerializeObject((MatchMakerState)this);

            gal.AttackerSideCounter    = AttackerSideCounter;
            gal.AttackerSideChangeTime = AttackerSideChangeTime;
            db.SubmitAndMergeChanges();
        }

        void StartChallenge(AttackOption attackOption)
        {
            Challenge     = attackOption;
            ChallengeTime = DateTime.UtcNow;
            AttackOptions.Clear();
            UpdateLobby();
        }

        void TasOnChannelUserAdded(object sender, TasEventArgs args)
        {
            string  chan     = args.ServerParams[0];
            string  userName = args.ServerParams[1];
            Faction faction  = factions.FirstOrDefault(x => x.Shortcut == chan);

            if (faction != null)
            {
                var db  = new ZkDataContext();
                var acc = Account.AccountByName(db, userName);
                if (acc != null && acc.CanPlayerPlanetWars())
                {
                    UpdateLobby(userName);
                }
            }
        }

        /// <summary>
        ///     Intercept channel messages for attacking/defending
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void TasOnPreviewSaid(object sender, CancelEventArgs <TasSayEventArgs> args)
        {
            if (args.Data.Text.StartsWith("!") && (args.Data.Place == TasSayEventArgs.Places.Channel || args.Data.Place == TasSayEventArgs.Places.Normal) &&
                args.Data.Origin == TasSayEventArgs.Origins.Player && args.Data.UserName != GlobalConst.NightwatchName)
            {
                int targetPlanetId;
                if (int.TryParse(args.Data.Text.Substring(1), out targetPlanetId))
                {
                    JoinPlanet(args.Data.UserName, targetPlanetId);
                }
            }
        }

        /// <summary>
        ///     Remove/reduce poll count due to lobby quits
        /// </summary>
        void TasOnUserRemoved(object sender, TasEventArgs args)
        {
            if (Challenge == null)
            {
                if (AttackOptions.Count > 0)
                {
                    string userName   = args.ServerParams[0];
                    int    sumRemoved = 0;
                    foreach (AttackOption aop in AttackOptions)
                    {
                        sumRemoved += aop.Attackers.RemoveAll(x => x == userName);
                    }
                    if (sumRemoved > 0)
                    {
                        UpdateLobby();
                    }
                }
            }
            else
            {
                string userName = args.ServerParams[0];
                if (Challenge.Defenders.RemoveAll(x => x == userName) > 0)
                {
                    UpdateLobby();
                }
            }
        }

        void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            try
            {
                if (Challenge == null)
                {
                    // attack timer
                    if (DateTime.UtcNow > GetAttackDeadline())
                    {
                        AttackerSideCounter++;
                        ResetAttackOptions();
                    }
                }
                else
                {
                    // accept timer
                    if (DateTime.UtcNow > GetAcceptDeadline())
                    {
                        if (Challenge.Defenders.Count >= Challenge.Attackers.Count - 1 && Challenge.Defenders.Count > 0)
                        {
                            AcceptChallenge();
                        }
                        else
                        {
                            RecordPlanetwarsLoss(Challenge);
                            AttackerSideCounter++;
                            ResetAttackOptions();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
            }
        }
        void tas_Said(object sender, TasSayEventArgs e)
        {
            if (e.UserName.Contains("Nightwatch"))
            {
                return;
            }

            if (e.Place == TasSayEventArgs.Places.Normal)
            {
                foreach (string command in adminCommands)
                {
                    if (e.Text.StartsWith("!" + command))
                    {
                        var db  = new ZkDataContext();
                        var acc = Account.AccountByLobbyID(db, tas.ExistingUsers[e.UserName].LobbyID);
                        if (!(acc.IsZeroKAdmin || acc.IsLobbyAdministrator))
                        {
                            return;
                        }
                        break;
                    }
                }

                if (e.Text.StartsWith("!kick"))
                {
                    var parts = e.Text.Split(' ');
                    if (!(parts.Length >= 2))
                    {
                        tas.Say(TasClient.SayPlace.User, e.UserName, "!kick [player] [reason]", false);
                    }
                    else
                    {
                        var player      = tas.ExistingUsers.FirstOrDefault(x => x.Key == parts[1]).Key;
                        var reasonParts = ((string[])parts.Clone()).ToList();
                        reasonParts.RemoveRange(0, 2);
                        string reason = string.Join(" ", reasonParts) ?? "";
                        if (player != null)
                        {
                            tas.AdminKickFromLobby(player, reason);
                        }
                        else
                        {
                            tas.Say(TasClient.SayPlace.User, e.UserName, "Not a valid player name", false);
                        }
                    }
                }
                else if (e.Text.StartsWith("!op"))
                {
                    var parts = e.Text.Split(' ');
                    if (parts.Length != 3)
                    {
                        tas.Say(TasClient.SayPlace.User, e.UserName, "!op [player] [channel]", false);
                    }
                    else
                    {
                        var player  = tas.ExistingUsers.FirstOrDefault(x => x.Key == parts[1]).Key;
                        var channel = parts[2];
                        if (player != null)
                        {
                            tas.Say(TasClient.SayPlace.User, "ChanServ", string.Format("!op {0} {1}", channel, player), false);
                            tas.Say(TasClient.SayPlace.User, e.UserName, string.Format("DEBUG: !op {0} {1}", channel, player), false);
                        }
                        else
                        {
                            tas.Say(TasClient.SayPlace.User, e.UserName, "Not a valid player name", false);
                        }
                    }
                }
                else if (e.Text.StartsWith("!changeaccountpass"))
                {
                    var parts = e.Text.Split(' ');
                    if (parts.Length != 3)
                    {
                        tas.Say(TasClient.SayPlace.User, e.UserName, "!changeaccountpass [player] [password (plaintext)]", false);
                    }
                    else
                    {
                        var password = PlasmaShared.Utils.HashLobbyPassword(parts[2]);
                        tas.SendRaw(string.Format("CHANGEACCOUNTPASS {0} {1}", parts[1], password));
                        tas.Say(TasClient.SayPlace.User, e.UserName, string.Format("DEBUG: CHANGEACCOUNTPASS {0} {1}", parts[1], password), false);
                    }
                }
                else if (e.Text.StartsWith("!chanserv"))
                {
                    var command = e.Text.Substring(9).TrimStart();
                    tas.Say(TasClient.SayPlace.User, "ChanServ", "!" + command, false);
                }
            }
        }
        static bool listOnlyThatLevelsModules = false;  // may cause bugs

        public static SpringBattleStartSetup GetSpringBattleStartSetup(BattleContext context)
        {
            try {
                AutohostMode mode = context.GetMode();
                var          ret  = new SpringBattleStartSetup();

                if (mode == AutohostMode.Planetwars)
                {
                    ret.BalanceTeamsResult = Balancer.BalanceTeams(context, true, null, null);
                    context.Players        = ret.BalanceTeamsResult.Players;
                }

                var commanderTypes = new LuaTable();
                var db             = new ZkDataContext();

                var accountIDsWithExtraComms = new List <int>();
                // calculate to whom to send extra comms
                if (mode == AutohostMode.Planetwars || mode == AutohostMode.SmallTeams || mode == AutohostMode.GameFFA ||
                    mode == AutohostMode.Teams || mode == AutohostMode.LowSkill || mode == AutohostMode.HighSkill)
                {
                    IOrderedEnumerable <IGrouping <int, PlayerTeam> > groupedByTeam =
                        context.Players.Where(x => !x.IsSpectator).GroupBy(x => x.AllyID).OrderByDescending(x => x.Count());
                    IGrouping <int, PlayerTeam> biggest = groupedByTeam.FirstOrDefault();
                    if (biggest != null)
                    {
                        foreach (var other in groupedByTeam.Skip(1))
                        {
                            int cnt = biggest.Count() - other.Count();
                            if (cnt > 0)
                            {
                                foreach (Account a in
                                         other.Select(x => db.Accounts.First(y => y.LobbyID == x.LobbyID)).OrderByDescending(x => x.Elo * x.EloWeight).Take(
                                             cnt))
                                {
                                    accountIDsWithExtraComms.Add(a.AccountID);
                                }
                            }
                        }
                    }
                }

                bool is1v1 = context.Players.Where(x => !x.IsSpectator).ToList().Count == 2 && context.Bots.Count == 0;



                Faction attacker = null;
                Faction defender = null;
                Planet  planet   = null;
                if (mode == AutohostMode.Planetwars)
                {
                    planet   = db.Galaxies.First(x => x.IsDefault).Planets.First(x => x.Resource.InternalName == context.Map);
                    attacker =
                        context.Players.Where(x => x.AllyID == 0 && !x.IsSpectator)
                        .Select(x => db.Accounts.First(y => y.LobbyID == x.LobbyID))
                        .Where(x => x.Faction != null)
                        .Select(x => x.Faction)
                        .First();

                    defender = planet.Faction;

                    if (attacker == defender)
                    {
                        defender = null;
                    }

                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                        Key = "attackingFaction", Value = attacker.Shortcut
                    });
                    if (defender != null)
                    {
                        ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                            Key = "defendingFaction", Value = defender.Shortcut
                        });
                    }
                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                        Key = "planet", Value = planet.Name
                    });
                }



                foreach (PlayerTeam p in context.Players)
                {
                    Account user = Account.AccountByLobbyID(db, p.LobbyID);
                    if (user != null)
                    {
                        var userParams = new List <SpringBattleStartSetup.ScriptKeyValuePair>();
                        ret.UserParameters.Add(new SpringBattleStartSetup.UserCustomParameters {
                            LobbyID = p.LobbyID, Parameters = userParams
                        });

                        bool userBanMuted = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanMute);
                        if (userBanMuted)
                        {
                            userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                Key = "muted", Value = "1"
                            });
                        }
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                        {
                            Key = "faction", Value = user.Faction != null ? user.Faction.Shortcut : ""
                        });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                        {
                            Key = "clan", Value = user.Clan != null ? user.Clan.Shortcut : ""
                        });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                            Key = "level", Value = user.Level.ToString()
                        });
                        double elo = mode == AutohostMode.Planetwars ? user.EffectivePwElo : (is1v1 ? user.Effective1v1Elo : user.EffectiveElo);
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                            Key = "elo", Value = Math.Round(elo).ToString()
                        });                                                                                                                // elo for ingame is just ordering for auto /take
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                            Key = "avatar", Value = user.Avatar
                        });

                        if (!p.IsSpectator)
                        {
                            if (mode == AutohostMode.Planetwars)
                            {
                                bool allied = user.Faction != null && defender != null && user.Faction != defender &&
                                              defender.HasTreatyRight(user.Faction, x => x.EffectPreventIngamePwStructureDestruction == true, planet);

                                if (!allied && user.Faction != null && (user.Faction == attacker || user.Faction == defender))
                                {
                                    userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                        Key = "canAttackPwStructures", Value = "1"
                                    });
                                }
                            }

                            var  pu = new LuaTable();
                            bool userUnlocksBanned    = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanUnlocks);
                            bool userCommandersBanned = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanCommanders);

                            if (!userUnlocksBanned)
                            {
                                if (mode != AutohostMode.Planetwars || user.Faction == null)
                                {
                                    foreach (Unlock unlock in user.AccountUnlocks.Select(x => x.Unlock))
                                    {
                                        pu.Add(unlock.Code);
                                    }
                                }
                                else
                                {
                                    foreach (Unlock unlock in
                                             user.AccountUnlocks.Select(x => x.Unlock).Union(user.Faction.GetFactionUnlocks().Select(x => x.Unlock)).Where(x => x.UnlockType == UnlockTypes.Unit))
                                    {
                                        pu.Add(unlock.Code);
                                    }
                                }
                            }

                            userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                Key = "unlocks", Value = pu.ToBase64String()
                            });

                            if (accountIDsWithExtraComms.Contains(user.AccountID))
                            {
                                userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                    Key = "extracomm", Value = "1"
                                });
                            }

                            var pc = new LuaTable();

                            if (!userCommandersBanned)
                            {
                                foreach (Commander c in user.Commanders.Where(x => x.Unlock != null && x.ProfileNumber <= GlobalConst.CommanderProfileCount))
                                {
                                    try {
                                        if (string.IsNullOrEmpty(c.Name) || c.Name.Any(x => x == '"'))
                                        {
                                            c.Name = c.CommanderID.ToString();
                                        }
                                        LuaTable morphTable = new LuaTable();
                                        pc["[\"" + c.Name + "\"]"] = morphTable;

                                        // process decoration icons
                                        LuaTable decorations = new LuaTable();
                                        foreach (Unlock d in
                                                 c.CommanderDecorations.Where(x => x.Unlock != null).OrderBy(
                                                     x => x.SlotID).Select(x => x.Unlock))
                                        {
                                            CommanderDecorationIcon iconData = db.CommanderDecorationIcons.FirstOrDefault(x => x.DecorationUnlockID == d.UnlockID);
                                            if (iconData != null)
                                            {
                                                string iconName = null, iconPosition = null;
                                                // FIXME: handle avatars and preset/custom icons
                                                if (iconData.IconType == (int)DecorationIconTypes.Faction)
                                                {
                                                    iconName = user.Faction != null ? user.Faction.Shortcut : null;
                                                }
                                                else if (iconData.IconType == (int)DecorationIconTypes.Clan)
                                                {
                                                    iconName = user.Clan != null ? user.Clan.Shortcut : null;
                                                }

                                                if (iconName != null)
                                                {
                                                    iconPosition = CommanderDecoration.GetIconPosition(d);
                                                    LuaTable entry = new LuaTable();
                                                    entry.Add("image", iconName);
                                                    decorations.Add("icon_" + iconPosition.ToLower(), entry);
                                                }
                                            }
                                            else
                                            {
                                                decorations.Add(d.Code);
                                            }
                                        }


                                        string prevKey = null;
                                        for (int i = 0; i <= GlobalConst.NumCommanderLevels; i++)
                                        {
                                            string key = string.Format("c{0}_{1}_{2}", user.AccountID, c.ProfileNumber, i);
                                            morphTable.Add(key);    // TODO: maybe don't specify morph series in player data, only starting unit

                                            var comdef = new LuaTable();
                                            commanderTypes[key] = comdef;

                                            comdef["chassis"] = c.Unlock.Code + i;

                                            var modules = new LuaTable();
                                            comdef["modules"] = modules;

                                            comdef["decorations"] = decorations;

                                            comdef["name"] = c.Name.Substring(0, Math.Min(25, c.Name.Length)) + " level " + i;

                                            //if (i < GlobalConst.NumCommanderLevels)
                                            //{
                                            //    comdef["next"] = string.Format("c{0}_{1}_{2}", user.AccountID, c.ProfileNumber, i+1);
                                            //}
                                            //comdef["owner"] = user.Name;

                                            if (i > 0)
                                            {
                                                comdef["cost"] = c.GetTotalMorphLevelCost(i);

                                                if (listOnlyThatLevelsModules)
                                                {
                                                    if (prevKey != null)
                                                    {
                                                        comdef["prev"] = prevKey;
                                                    }
                                                    prevKey = key;
                                                    foreach (Unlock m in
                                                             c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel == i && x.Unlock != null).OrderBy(
                                                                 x => x.Unlock.UnlockType).ThenBy(x => x.SlotID).Select(x => x.Unlock))
                                                    {
                                                        modules.Add(m.Code);
                                                    }
                                                }
                                                else
                                                {
                                                    foreach (Unlock m in
                                                             c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel <= i && x.Unlock != null).OrderBy(
                                                                 x => x.Unlock.UnlockType).ThenBy(x => x.SlotID).Select(x => x.Unlock))
                                                    {
                                                        modules.Add(m.Code);
                                                    }
                                                }
                                            }
                                        }
                                    } catch (Exception ex) {
                                        Trace.TraceError(ex.ToString());
                                        throw new ApplicationException(
                                                  string.Format("Error processing commander: {0} - {1} of player {2} - {3}",
                                                                c.CommanderID,
                                                                c.Name,
                                                                user.AccountID,
                                                                user.Name),
                                                  ex);
                                    }
                                }
                            }
                            else
                            {
                                userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                    Key = "jokecomm", Value = "1"
                                });
                            }

                            userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                                Key = "commanders", Value = pc.ToBase64String()
                            });
                        }
                    }
                }

                ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair {
                    Key = "commanderTypes", Value = commanderTypes.ToBase64String()
                });
                if (mode == AutohostMode.Planetwars)
                {
                    string owner = planet.Faction != null ? planet.Faction.Shortcut : "";

                    var pwStructures = new LuaTable();
                    foreach (PlanetStructure s in planet.PlanetStructures.Where(x => x.StructureType != null && !string.IsNullOrEmpty(x.StructureType.IngameUnitName)))
                    {
                        pwStructures.Add("s" + s.StructureTypeID,
                                         new LuaTable
                        {
                            { "unitname", s.StructureType.IngameUnitName },
                            //{ "isDestroyed", s.IsDestroyed ? true : false },
                            { "name", string.Format("{0} {1} ({2})", owner, s.StructureType.Name, s.Account != null ? s.Account.Name:"unowned") },
                            { "description", s.StructureType.Description }
                        });
                    }
                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                    {
                        Key = "planetwarsStructures", Value = pwStructures.ToBase64String()
                    });
                }

                return(ret);
            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
                throw;
            }
        }
        public static PlayerJoinResult AutohostPlayerJoined(BattleContext context, int accountID)
        {
            var          res  = new PlayerJoinResult();
            var          db   = new ZkDataContext();
            AutohostMode mode = context.GetMode();

            if (mode == AutohostMode.Planetwars)
            {
                Planet planet = db.Galaxies.Single(x => x.IsDefault).Planets.SingleOrDefault(x => x.Resource.InternalName == context.Map);
                if (planet == null)
                {
                    res.PublicMessage = "Invalid map";
                    return(res);
                }
                Account account = Account.AccountByLobbyID(db, accountID); // accountID is in fact lobbyID

                if (account != null)
                {
                    if (account.Level < context.GetConfig().MinLevel)
                    {
                        res.PrivateMessage = string.Format("Sorry, PlanetWars is competive online campaign for experienced players. You need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots.  You can still spectate this game, however.",
                                                           context.GetConfig().MinLevel);
                        res.ForceSpec = true;
                        return(res);
                    }

                    /*
                     * if (account.Faction == null)
                     * {
                     *  res.PrivateMessage =
                     *      string.Format(
                     *          "{0} this is competitive PlanetWars campaign server. Join a clan to conquer the galaxy http://zero-k.info/Factions",
                     *          account.Name);
                     *  return res;
                     * }*/

                    string owner = "";
                    if (planet.Account != null)
                    {
                        owner = planet.Account.Name;
                    }
                    string facRoles = string.Join(",",
                                                  account.AccountRolesByAccountID.Where(x => !x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(facRoles))
                    {
                        facRoles += " of " + account.Faction.Name + ", ";
                    }

                    string clanRoles = string.Join(",",
                                                   account.AccountRolesByAccountID.Where(x => x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(clanRoles))
                    {
                        clanRoles += " of " + account.Clan.ClanName;
                    }

                    res.PublicMessage = string.Format("Greetings {0} {1}{2}, welcome to {3} planet {4} http://zero-k.info/PlanetWars/Planet/{5}",
                                                      account.Name,
                                                      facRoles,
                                                      clanRoles,
                                                      owner,
                                                      planet.Name,
                                                      planet.PlanetID);

                    return(res);
                }
            }
            Account acc = Account.AccountByLobbyID(db, accountID); // accountID is in fact lobbyID

            if (acc != null)
            {
                AutohostConfig config = context.GetConfig();
                if (acc.Level < config.MinLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots. You can still spectate this game, however.",
                                                       config.MinLevel);
                    res.ForceSpec = true;
                    return(res);
                }
                else if (acc.Level > config.MaxLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, your level must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                       config.MaxLevel);
                    res.ForceSpec = true;
                    return(res);
                }

                // FIXME: use 1v1 Elo for 1v1
                if (acc.EffectiveElo < config.MinElo)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to have an Elo rating of at least {0} to play here. Win games against human opponents to raise your Elo. You can still spectate this game, however.",
                                                       config.MinElo);
                    res.ForceSpec = true;
                    return(res);
                }
                else if (acc.EffectiveElo > config.MaxElo)
                {
                    res.PrivateMessage = string.Format("Sorry, your Elo rating must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                       config.MaxElo);
                    res.ForceSpec = true;
                    return(res);
                }
            }

            return(null);
        }
Beispiel #8
0
        public AuthService(TasClient client)
        {
            this.client = client;

            /*
             * this.client.Input += (s, e) =>
             * {
             * Console.WriteLine(e.Command +" "+ Utils.Glue(e.Args));
             * };
             * this.client.Output += (s, e) =>
             * {
             * Console.WriteLine(e.Data.Key + " " +Utils.Glue(e.Data.Value.Select(x=>x.ToString()).ToArray()));
             * };*/

            this.client.LoginAccepted += (s, e) =>
            {
                requests.Clear();
                client.JoinChannel(ModeratorChannel);
                client.JoinChannel(Top20Channel);
                using (var db = new ZkDataContext()) foreach (var fac in db.Factions.Where(x => !x.IsDeleted))
                    {
                        client.JoinChannel(fac.Shortcut);
                    }
            };

            this.client.TestLoginAccepted += (s, e) =>
            {
                RequestInfo entry;
                if (requests.TryGetValue(client.MessageID, out entry))
                {
                    entry.CorrectName = e.ServerParams[0];
                    entry.LobbyID     = Convert.ToInt32(e.ServerParams[1]);
                    if (client.ExistingUsers.ContainsKey(entry.CorrectName))
                    {
                        entry.User = client.ExistingUsers[entry.CorrectName];
                    }
                    entry.WaitHandle.Set();
                }

                requests.TryRemove(client.MessageID, out entry);
            };

            this.client.UserAdded += (s, e) =>
            {
                using (var db = new ZkDataContext())
                {
                    var acc = Account.AccountByLobbyID(db, e.Data.LobbyID);
                    if (acc != null)
                    {
                        this.client.Extensions.PublishAccountData(acc);
                        if (acc.SpringieLevel > 2 || acc.IsZeroKAdmin)
                        {
                            client.ForceJoinChannel(e.Data.Name, ModeratorChannel);
                        }
                        if (topPlayers.IsTop20(e.Data.LobbyID))
                        {
                            client.ForceJoinChannel(e.Data.Name, Top20Channel);
                        }
                        if (acc.Clan != null)
                        {
                            client.ForceJoinChannel(e.Data.Name, acc.Clan.GetClanChannel(), acc.Clan.Password);
                        }
                        if (acc.Faction != null && acc.Level >= GlobalConst.FactionChannelMinLevel && acc.CanPlayerPlanetWars())
                        {
                            client.ForceJoinChannel(e.Data.Name, acc.Faction.Shortcut);
                        }
                    }
                    client.RequestUserIP(e.Data.Name);
                    client.RequestUserID(e.Data.Name);
                }
            };

            this.client.UserIDRecieved += (sender, args) =>
            {
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        using (var db = new ZkDataContext())
                        {
                            var acc     = Account.AccountByName(db, args.Name);
                            var penalty = Punishment.GetActivePunishment(acc != null ? acc.AccountID : 0, null, args.ID, x => x.BanLobby, db);

                            if (penalty != null)
                            {
                                client.AdminKickFromLobby(args.Name,
                                                          string.Format("Banned until {0} (ID match to {1}), reason: {2}", penalty.BanExpires, penalty.AccountByAccountID.Name, penalty.Reason));
                            }
                            ;

                            if (acc != null && args.ID != 0)
                            {
                                var entry = acc.AccountUserIDS.FirstOrDefault(x => x.UserID == args.ID);
                                if (entry == null)
                                {
                                    entry = new AccountUserID {
                                        AccountID = acc.AccountID, UserID = args.ID, FirstLogin = DateTime.UtcNow
                                    };
                                    db.AccountUserIDS.InsertOnSubmit(entry);
                                }
                                entry.LoginCount++;
                                entry.LastLogin = DateTime.UtcNow;
                            }

                            Account accAnteep  = db.Accounts.FirstOrDefault(x => x.AccountID == 4490);
                            bool isAnteepSmurf = accAnteep.AccountUserIDS.Any(x => x.UserID == args.ID);
                            if (isAnteepSmurf)
                            {
                                client.Say(TasClient.SayPlace.Channel, ModeratorChannel, String.Format("Suspected Anteep smurf: {0} (ID match {1}) {2}", args.Name, args.ID,
                                                                                                       acc != null ? "http://zero-k.info/Users/Detail/" + acc.AccountID : ""), false);
                            }

                            if (args.ID != 0 && args.ID < 1000)
                            {
                                client.Say(TasClient.SayPlace.Channel, ModeratorChannel, String.Format("Suspected Anteep smurf: {0} (too short userID {1}) {2}", args.Name, args.ID,
                                                                                                       acc != null ? "http://zero-k.info/Users/Detail/" + acc.AccountID : ""), false);
                            }

                            db.SubmitChanges();
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Error getting user ID: {0}", ex);
                    }
                });
            };

            this.client.UserIPRecieved += (sender, args) =>
            {
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        Account acc = null;
                        using (var db = new ZkDataContext())
                        {
                            acc = Account.AccountByName(db, args.Name);

                            var penalty = Punishment.GetActivePunishment(acc != null ? acc.AccountID : 0, args.IP, null, x => x.BanLobby, db);
                            if (penalty != null)
                            {
                                client.AdminKickFromLobby(args.Name,
                                                          string.Format("Banned until {0} (IP match to {1}), reason: {2}", penalty.BanExpires, penalty.AccountByAccountID.Name, penalty.Reason));
                            }
                            if (acc != null)
                            {
                                var entry = acc.AccountIPS.FirstOrDefault(x => x.IP == args.IP);
                                if (entry == null)
                                {
                                    entry = new AccountIP {
                                        AccountID = acc.AccountID, IP = args.IP, FirstLogin = DateTime.UtcNow
                                    };
                                    db.AccountIPS.InsertOnSubmit(entry);
                                }
                                entry.LoginCount++;
                                entry.LastLogin = DateTime.UtcNow;
                            }
                            db.SubmitChanges();
                        }

                        try
                        {
                            if (acc == null || !acc.HasVpnException)
                            {
                                if (GlobalConst.VpnCheckEnabled)
                                {
                                    // check user IP against http://dnsbl.tornevall.org
                                    // does not catch all smurfs
                                    // mostly false positives, do not use
                                    var reversedIP = string.Join(".", args.IP.Split('.').Reverse().ToArray());
                                    try
                                    {
                                        var resolved = Dns.GetHostEntry(string.Format("{0}.dnsbl.tornevall.org", reversedIP)).AddressList;
                                        if (resolved.Length > 0)
                                        {
                                            client.Say(TasClient.SayPlace.Channel, ModeratorChannel, String.Format("User {0} {3} has IP {1} on dnsbl.tornevall.org ({2} result/s)",
                                                                                                                   args.Name, args.IP, resolved.Length, acc != null ? "http://zero-k.info/Users/Detail/" + acc.AccountID : ""), false);
                                            //client.AdminKickFromLobby(args.Name,
                                            //                      "Connection using proxy or VPN is not allowed! (You can ask for exception). See http://dnsbl.tornevall.org/removal.php to get your IP removed from the blacklist.");
                                        }
                                    }
                                    catch (System.Net.Sockets.SocketException sockEx)
                                    {
                                        // not in database, do nothing
                                    }
                                }
                                using (var db = new ZkDataContext())
                                {
                                    Account accAnteep  = db.Accounts.FirstOrDefault(x => x.AccountID == 4490);
                                    bool isAnteepSmurf = accAnteep.AccountIPS.Any(x => x.IP == args.IP);
                                    if (isAnteepSmurf)
                                    {
                                        client.Say(TasClient.SayPlace.Channel, ModeratorChannel, String.Format("Suspected Anteep smurf: {0} (IP match {1}) {2}", args.Name, args.IP,
                                                                                                               acc != null ? "http://zero-k.info/Users/Detail/" + acc.AccountID : ""), false);
                                    }
                                }

                                using (ZkDataContext db = new ZkDataContext())
                                {
                                    for (int i = 0; i <= 1; i++)
                                    {
                                        var whois = new Whois();
                                        var data  = whois.QueryByIp(args.IP, i == 1);

                                        if (!data.ContainsKey("netname"))
                                        {
                                            data["netname"] = "UNKNOWN NETNAME";
                                        }
                                        if (!data.ContainsKey("org-name"))
                                        {
                                            data["org-name"] = "UNKNOWN ORG";
                                        }
                                        if (!data.ContainsKey("abuse-mailbox"))
                                        {
                                            data["abuse-mailbox"] = "no mailbox";
                                        }
                                        if (!data.ContainsKey("notify"))
                                        {
                                            data["notify"] = "no notify address";
                                        }
                                        if (!data.ContainsKey("role"))
                                        {
                                            data["role"] = "UNKNOWN ROLE";
                                        }
                                        if (!data.ContainsKey("descr"))
                                        {
                                            data["descr"] = "no description";
                                        }
                                        if (!data.ContainsKey("remarks"))
                                        {
                                            data["remarks"] = "no remarks";
                                        }

                                        var blockedCompanies = db.BlockedCompanies.Select(x => x.CompanyName.ToLower()).ToList();
                                        var blockedHosts     = db.BlockedHosts.Select(x => x.HostName).ToList();

                                        /*if (acc.Country == "MY")
                                         * {
                                         *  client.Say(TasClient.SayPlace.User, "KingRaptor", String.Format("USER {0}\nnetname: {1}\norgname: {2}\ndescr: {3}\nabuse-mailbox: {4}",
                                         *      acc.Name, data["netname"], data["org-name"], data["descr"], data["abuse-mailbox"]), false);
                                         * }*/
                                        if (blockedHosts.Any(x => data["abuse-mailbox"].Contains(x)) || (blockedHosts.Any(x => data["notify"].Contains(x))))
                                        {
                                            client.AdminKickFromLobby(args.Name, "Connection using proxy or VPN is not allowed! (You can ask for exception)");
                                        }
                                        foreach (string company in blockedCompanies)
                                        {
                                            if (data["netname"].ToLower().Contains(company) || data["org-name"].ToLower().Contains(company) || data["descr"].ToLower().Contains(company) || data["role"].ToLower().Contains(company) || data["remarks"].ToLower().Contains(company))
                                            {
                                                client.AdminKickFromLobby(args.Name, "Connection using proxy or VPN is not allowed! (You can ask for exception)");
                                                break;
                                            }
                                        }

                                        var hostname = Dns.GetHostEntry(args.IP).HostName;
                                        if (blockedHosts.Any(hostname.Contains))
                                        {
                                            client.AdminKickFromLobby(args.Name, "Connection using proxy or VPN is not allowed! (You can ask for exception)");
                                        }
                                    }
                                }
                            }
                        }
                        catch (System.Net.Sockets.SocketException sockEx)
                        {
                            // do nothing
                        }
                        catch (Exception ex)
                        {
                            Trace.TraceError("VPN check error: {0}", ex);
                            client.Say(TasClient.SayPlace.Channel, ModeratorChannel, ex.ToString(), false);
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Error getting user IP: {0}", ex);
                        //client.Say(TasClient.SayPlace.User, "KingRaptor", ex.ToString(), false);
                    }
                });
            };

            this.client.UserStatusChanged += (s, e) =>
            {
                var user = client.ExistingUsers[e.ServerParams[0]];
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        using (var db = new ZkDataContext()) UpdateUser(user.LobbyID, user.Name, user, null, db);
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError(ex.ToString());
                    }
                },
                                      TaskCreationOptions.LongRunning);
            };

            this.client.BattleUserJoined += (s, e) =>
            {
                var battle  = client.ExistingBattles[e.BattleID];
                var founder = battle.Founder;
                if (founder.IsSpringieManaged)
                {
                    try
                    {
                        var user = client.ExistingUsers[e.UserName];

                        /*  obsolete; all major lobbies have multiengine support
                         * if (!user.IsZkLobbyUser && !user.IsNotaLobby && battle.EngineVersion != client.ServerSpringVersion &&
                         *  battle.EngineVersion != client.ServerSpringVersion + ".0") {
                         *  client.Say(TasClient.SayPlace.User,
                         *             user.Name,
                         *             string.Format(
                         *                 "ALERT! YOU WILL DESYNC!! You NEED SPRING ENGINE {0} to play here. Simply join the game with Zero-K lobby ( http://zero-k.info/Wiki/Download ) OR get the engine from http://springrts.com/dl/buildbot/default/ OR build it on your Linux: http://springrts.com/wiki/Building_Spring_on_Linux ",
                         *                 battle.EngineVersion),
                         *             false);
                         * }
                         */
                        using (var db = new ZkDataContext())
                        {
                            var acc   = Account.AccountByLobbyID(db, user.LobbyID);
                            var name  = founder.Name.TrimNumbers();
                            var aconf = db.AutohostConfigs.FirstOrDefault(x => x.Login == name);
                            if (acc != null && user != null && aconf != null &&
                                (acc.LastLobbyVersionCheck == null || DateTime.UtcNow.Subtract(acc.LastLobbyVersionCheck.Value).TotalDays > 3) &&
                                aconf.AutohostMode != 0)
                            {
                                client.RequestLobbyVersion(user.Name);
                            }

                            /*
                             * if (acc != null)
                             * {
                             *  int numIDs = acc.AccountUserIDS != null ? acc.AccountUserIDS.Count : 0;
                             *  if (numIDs == 0) client.Say(TasClient.SayPlace.User, "KingRaptor", string.Format("USER {0} joined battle {1}; has {2} userIDs; lobby version {3}", acc.Name, founder.Name, numIDs, acc.LobbyVersion), false);
                             * }
                             * else
                             *  client.Say(TasClient.SayPlace.User, "KingRaptor", string.Format("USER {0} joined battle {1}", e.UserName + " (NO ACCOUNT)", founder.Name), false);
                             *
                             * if (acc != null)
                             * {
                             *  if (!acc.AccountUserIDS.Any())
                             *  {
                             *      string reason = string.Format("Sorry you are using unsupported lobby ({0}), please upgrade or use Zero-K Lobby, Weblobby or SpringLobby", acc.LobbyVersion);
                             *      client.Say(TasClient.SayPlace.User, user.Name, reason, false);
                             *      client.Say(TasClient.SayPlace.User, founder.Name, string.Format("!kick {0} {1}", acc.LobbyVersion, reason), false);
                             *  }
                             * }*/
                        }
                    }
                    catch (Exception ex)
                    {
                        //client.Say(TasClient.SayPlace.User, "KingRaptor", ex.ToString(), false);
                        Trace.TraceError("Error procesisng battle user joined: {0}", ex);
                    }
                }
            };

            this.client.TestLoginDenied += (s, e) =>
            {
                RequestInfo entry;
                if (requests.TryGetValue(client.MessageID, out entry))
                {
                    entry.WaitHandle.Set();
                }
                requests.TryRemove(client.MessageID, out entry);
            };

            this.client.UserLobbyVersionRecieved += (s, e) =>
            {
                using (var db = new ZkDataContext())
                {
                    var acc = Account.AccountByName(db, e.Name);
                    if (acc != null)
                    {
                        acc.LobbyVersion          = e.LobbyVersion;
                        acc.LastLobbyVersionCheck = DateTime.UtcNow;
                        db.SubmitAndMergeChanges();
                        if (!acc.LobbyVersion.StartsWith("ZK"))
                        {
                            // FIXME abma broke this (LobbyVersion is now some huge-ass integer instead)
                            //client.Say(TasClient.SayPlace.User,
                            //           e.Name,
                            //           string.Format(
                            //               "WARNING: You are connected using {0} which is not fully compatible with this host. Please use Zero-K lobby. Download it from http://zero-k.info   NOTE: to play all Spring games with Zero-K lobby, untick \"Official games\" on its multiplayer tab. Thank you!",
                            //               e.LobbyVersion),
                            //           false);
                        }
                    }
                }
            };

            this.client.BattleFound +=
                (s, e) => { if (e.Data.Founder.IsZkLobbyUser && !e.Data.Founder.IsBot)
                            {
                                client.SetBotMode(e.Data.Founder.Name, true);
                            }
            };

            this.client.ChannelUserAdded += (sender, args) =>
            {
                try
                {
                    var channel = args.ServerParams[0];
                    var user    = args.ServerParams[1];
                    if (channel == ModeratorChannel)
                    {
                        var u = client.ExistingUsers[user];
                        if (u.SpringieLevel <= 2 && !u.IsZeroKAdmin)
                        {
                            client.ForceLeaveChannel(user, ModeratorChannel);
                        }
                    }
                    else if (channel == Top20Channel)
                    {
                        var u = client.ExistingUsers[user];
                        if (!topPlayers.IsTop20(u.LobbyID) && u.Name != client.UserName)
                        {
                            client.ForceLeaveChannel(user, Top20Channel);
                        }
                    }
                    else
                    {
                        using (var db = new ZkDataContext())
                        {
                            var fac = db.Factions.FirstOrDefault(x => x.Shortcut == channel);
                            if (fac != null)
                            {
                                // faction channel
                                var u   = client.ExistingUsers[user];
                                var acc = Account.AccountByLobbyID(db, u.LobbyID);
                                if (acc == null || acc.FactionID != fac.FactionID || acc.Level < GlobalConst.FactionChannelMinLevel)
                                {
                                    client.ForceLeaveChannel(user, channel);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Error procesisng channel user added: {0}", ex);
                }
            };
            this.client.ChannelUserRemoved += (sender, args) =>
            {
                try
                {
                    var channel = args.ServerParams[0];
                    var user    = args.ServerParams[1];
                    if (channel == ModeratorChannel)
                    {
                        var u = client.ExistingUsers[user];
                        if (u.SpringieLevel > 2 || u.IsZeroKAdmin)
                        {
                            client.ForceJoinChannel(user, ModeratorChannel);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Error procesisng channel user added: {0}", ex);
                }
            };
        }
Beispiel #9
0
        void tas_Said(object sender, TasSayEventArgs e)
        {
            if (e.UserName.Contains("Nightwatch"))
            {
                return;
            }

            if (e.Place == TasSayEventArgs.Places.Normal)
            {
                if (e.Text.StartsWith("!move"))
                {
                    var db  = new ZkDataContext();
                    var acc = Account.AccountByLobbyID(db, tas.ExistingUsers[e.UserName].LobbyID);
                    if (acc.IsZeroKAdmin || acc.IsLobbyAdministrator)
                    {
                        var parts = e.Text.Split(' ');
                        if (parts.Length != 3)
                        {
                            tas.Say(TasClient.SayPlace.User, e.UserName, "!move [from] [to]", false);
                        }
                        else
                        {
                            var from = tas.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == parts[1]);
                            var to   = tas.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == parts[2]);
                            if (from != null && to != null)
                            {
                                foreach (var b in from.Users)
                                {
                                    if (!b.LobbyUser.IsInGame && b.Name != from.Founder.Name)
                                    {
                                        tas.ForceJoinBattle(b.Name, to.BattleID);
                                    }
                                }
                            }
                            else
                            {
                                tas.Say(TasClient.SayPlace.User, e.UserName, "Not a valid battle host name", false);
                            }
                        }
                    }
                }
                // split players evenly into two games by median elo -> expand to specify proportion to shunt?
                // TODO: split players and specs separately
                else if (e.Text.StartsWith("!splitplayers"))
                {
                    var db  = new ZkDataContext();
                    var acc = Account.AccountByLobbyID(db, tas.ExistingUsers[e.UserName].LobbyID);
                    if (acc.IsZeroKAdmin || acc.IsLobbyAdministrator)
                    {
                        var parts = e.Text.Split(' ');
                        if (parts.Length != 3)
                        {
                            tas.Say(TasClient.SayPlace.User, e.UserName, "!splitplayers [from] [to]", false);
                        }
                        else
                        {
                            var from = tas.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == parts[1]);
                            var to   = tas.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == parts[2]);
                            if (from != null && to != null)
                            {
                                var list   = from.Users.Where(x => !x.LobbyUser.IsInGame && x.Name != from.Founder.Name && !x.IsSpectator).OrderBy(x => x.LobbyUser.EffectiveElo);
                                var toMove = list.Take(list.Count() / 2);
                                foreach (var b in toMove)
                                {
                                    tas.ForceJoinBattle(b.Name, to.BattleID);
                                }
                            }
                            else
                            {
                                tas.Say(TasClient.SayPlace.User, e.UserName, "Not a valid battle host name", false);
                            }
                        }
                    }
                }
            }
        }