示例#1
0
 static void SpecPlayerOnCondition(PlayerTeam player, Account account, string userMessage)
 {
     player.IsSpectator = true;
     AuthServiceClient.SendLobbyMessage(account, userMessage);
 }
示例#2
0
        public static void AutoClosePolls()
        {
            var db = new ZkDataContext();

            foreach (var p in db.Polls.Where(x => x.IsHeadline && x.ExpireBy != null && x.ExpireBy < DateTime.UtcNow && x.RoleTypeID != null).ToList())
            {
                var yes = p.PollVotes.Count(x => x.PollOption.OptionText == "Yes");
                var no  = p.PollVotes.Count(x => x.PollOption.OptionText == "No");
                var acc = p.AccountByRoleTargetAccountID;
                if (yes > no)
                {
                    if (p.RoleIsRemoval)
                    {
                        var toDelete = db.AccountRoles.Where(x => x.AccountID == acc.AccountID && x.RoleTypeID == p.RoleTypeID);
                        db.AccountRoles.DeleteAllOnSubmit(toDelete);
                        db.Events.InsertOnSubmit(Global.CreateEvent("{0} was removed from the {1} role of {2} by a vote - {3} for, {4} against", acc, (object)p.Clan ?? p.Faction, p.RoleType, yes, no));

                        db.SubmitAndMergeChanges();

                        AuthServiceClient.SendLobbyMessage(acc, string.Format("You were recalled from the function of {0} by a vote", p.RoleType.Name));
                    }
                    else
                    {
                        if (!acc.AccountRolesByAccountID.Any(x => x.RoleTypeID == p.RoleTypeID))
                        {
                            Account previous = null;
                            if (p.RoleType.IsOnePersonOnly)
                            {
                                var entries = db.AccountRoles.Where(x => x.RoleTypeID == p.RoleTypeID && (p.RoleType.IsClanOnly ? x.ClanID == p.RestrictClanID : x.FactionID == p.RestrictFactionID)).ToList();

                                if (entries.Any())
                                {
                                    previous = entries.First().AccountByAccountID;
                                    db.AccountRoles.DeleteAllOnSubmit(entries);
                                    db.SubmitAndMergeChanges();
                                }
                            }

                            var entry = new AccountRole()
                            {
                                AccountByAccountID = acc,
                                Inauguration       = DateTime.UtcNow,
                                Clan     = p.Clan,
                                Faction  = p.Faction,
                                RoleType = p.RoleType
                            };
                            acc.AccountRolesByAccountID.Add(entry);
                            if (previous == null)
                            {
                                db.Events.InsertOnSubmit(Global.CreateEvent("{0} was elected for the {1} role of {2} by a vote - {3} for, {4} against",
                                                                            acc,
                                                                            (object)p.Clan ?? p.Faction,
                                                                            p.RoleType,
                                                                            yes,
                                                                            no));
                            }

                            else
                            {
                                db.Events.InsertOnSubmit(Global.CreateEvent("{0} was elected for the {1} role of {2} by a vote, replacing {3} - {4} for, {5} against",
                                                                            acc,
                                                                            (object)p.Clan ?? p.Faction,
                                                                            p.RoleType,
                                                                            previous,
                                                                            yes,
                                                                            no));
                            }

                            AuthServiceClient.SendLobbyMessage(acc, string.Format("Congratulations!! You were elected into a function of {0} by a vote", p.RoleType.Name));
                        }
                    }
                }

                p.IsHeadline = false;
                db.Polls.DeleteOnSubmit(p);
            }
            db.SubmitAndMergeChanges();
        }
示例#3
0
        public static BalanceTeamsResult BalanceTeams(string autoHost, string map, string mod, List <AccountTeam> currentTeams, List <BotTeam> currentBots)
        {
            var mode = ContentService.GetModeFromHost(autoHost);

            if (currentTeams.Count < 1)
            {
                return(new BalanceTeamsResult());
            }
            using (var db = new ZkDataContext())
            {
                var res = new BalanceTeamsResult();
                res.Message = "";
                var idList  = currentTeams.Select(x => x.AccountID).ToList();
                var players = new List <Account>();

                foreach (var p in idList.Select(x => db.Accounts.First(y => y.LobbyID == x)))
                {
                    /*if (p.ClanID == null)
                     * {
                     *  //res.Message += string.Format("{0} cannot play, must join a clan first http://zero-k.info/Planetwars/ClanList\n", p.Name);
                     *  //AuthServiceClient.SendLobbyMessage(p, "To play here, join a clan first http://zero-k.info/Planetwars/ClanList");
                     * }*/
                    /*if (p.Clan != null && !p.Name.Contains(p.Clan.Shortcut))
                     * {
                     *  res.Message += string.Format("{0} cannot play, name must contain clan tag {1}\n", p.Name, p.Clan.Shortcut);
                     *  AuthServiceClient.SendLobbyMessage(p,
                     *                                     string.Format(
                     *                                         "Your name must contain clan tag {0}, rename for example by saying: /rename [{0}]{1}",
                     *                                         p.Clan.Shortcut,
                     *                                         p.Name));
                     * }*/
                    if (p.Level < GlobalConst.MinPlanetWarsLevel)
                    {
                        res.Message += string.Format("{0} cannot play, his level is {1}, minimum level is {2}\n",
                                                     p.Name,
                                                     p.Level,
                                                     GlobalConst.MinPlanetWarsLevel);
                        AuthServiceClient.SendLobbyMessage(p,
                                                           string.Format(
                                                               "Sorry, PlanetWars is competive online campaign for experienced players. You need to be at least level 5 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 observe this game however."));
                    }
                    else
                    {
                        players.Add(p);
                    }
                }
                var clans    = players.Where(x => x.Clan != null).Select(x => x.Clan).ToList();
                var treaties = new Dictionary <Tuple <Clan, Clan>, EffectiveTreaty>();
                var planet   = db.Galaxies.Single(x => x.IsDefault).Planets.Single(x => x.Resource.InternalName == map);

                // bots game
                if (planet.PlanetStructures.Any(x => !string.IsNullOrEmpty(x.StructureType.EffectBots)))
                {
                    var teamID = 0;
                    for (var i = 0; i < players.Count; i++)
                    {
                        res.BalancedTeams.Add(new AccountTeam()
                        {
                            AccountID = players[i].LobbyID ?? 0, Name = players[i].Name, AllyID = 0, TeamID = teamID++
                        });
                    }
                    int cnt = 1;
                    foreach (var b in planet.PlanetStructures.Select(x => x.StructureType).Where(x => !string.IsNullOrEmpty(x.EffectBots)))
                    {
                        res.Bots.Add(new BotTeam()
                        {
                            AllyID = 1, BotAI = b.EffectBots, TeamID = teamID++, BotName = "Aliens" + cnt++
                        });
                    }

                    res.Message += string.Format("This planet is infested by aliens, fight for your survival");
                    return(res);
                }

                var planetFactionId  = planet.Account != null ? planet.Account.FactionID ?? 0 : 0;
                var attackerFactions =
                    planet.AccountPlanets.Where(x => x.DropshipCount > 0 && x.Account.FactionID != null).Select(x => (x.Account.FactionID ?? 0)).
                    Distinct().ToList();

                if (currentTeams.Count < 2)
                {
                    return new BalanceTeamsResult()
                           {
                               Message = "Not enough players"
                           }
                }
                ;

                for (var i = 1; i < clans.Count; i++)
                {
                    for (var j = 0; j < i; j++)
                    {
                        var treaty = clans[i].GetEffectiveTreaty(clans[j]);
                        treaties[Tuple.Create(clans[i], clans[j])] = treaty;
                        treaties[Tuple.Create(clans[j], clans[i])] = treaty;

                        // if treaty is neutral but they send ships - mark as "war"
                        if (planet.OwnerAccountID != null && treaty.AllyStatus == AllyStatus.Neutral)
                        {
                            if (clans[i].ClanID == planet.Account.ClanID &&
                                planet.AccountPlanets.Any(x => x.Account.ClanID == clans[j].ClanID && x.DropshipCount > 0))
                            {
                                treaty.AllyStatus = AllyStatus.War;
                            }
                            else if (clans[j].ClanID == planet.Account.ClanID &&
                                     planet.AccountPlanets.Any(x => x.Account.ClanID == clans[i].ClanID && x.DropshipCount > 0))
                            {
                                treaty.AllyStatus = AllyStatus.War;
                            }
                        }
                    }
                }

                var sameTeamScore = new double[players.Count, players.Count];
                for (var i = 1; i < players.Count; i++)
                {
                    for (var j = 0; j < i; j++)
                    {
                        var c1     = players[i].Clan;
                        var c2     = players[j].Clan;
                        var f1     = players[i].FactionID ?? -1;
                        var f2     = players[i].FactionID ?? -1;
                        var points = 0.0;
                        if (players[i].FactionID != null && players[i].FactionID == players[j].FactionID)
                        {
                            points = 3;                                                                               // same faction weight 1
                        }
                        if (c1 != null && c2 != null)
                        {
                            if (c1 == c2)
                            {
                                points = 4;
                            }
                            else
                            {
                                var treaty = treaties[Tuple.Create(players[i].Clan, players[j].Clan)];
                                if (treaty.AllyStatus == AllyStatus.Alliance)
                                {
                                    points = 2;
                                }
                                else if (treaty.AllyStatus == AllyStatus.Ceasefire)
                                {
                                    points = 1;
                                }
                                else if (treaty.AllyStatus == AllyStatus.War)
                                {
                                    points = -3;
                                }
                                if (treaty.AllyStatus == AllyStatus.Neutral && f1 != f2)
                                {
                                    if ((planetFactionId == f1 && attackerFactions.Contains(f2)) ||
                                        (planetFactionId == f2 && attackerFactions.Contains(f1)))
                                    {
                                        points = -3;
                                    }
                                }
                            }
                        }
                        else if (f1 != f2)
                        {
                            if ((planetFactionId == f1 && attackerFactions.Contains(f2)) ||
                                (planetFactionId == f2 && attackerFactions.Contains(f1)))
                            {
                                points = -3;
                            }
                        }

                        sameTeamScore[i, j] = points;
                        sameTeamScore[j, i] = points;
                        //res.Message += string.Format("{0} + {1} = {2} \n", players[i].Name, players[j].Name, points);
                    }
                }

                var playerScoreMultiplier = new double[players.Count];
                for (var i = 0; i < players.Count; i++)
                {
                    var mult   = 1.0;
                    var player = players[i];
                    if (planet.OwnerAccountID == player.AccountID)
                    {
                        mult += 1;                                            // owner
                    }
                    else if (planet.Account != null && planet.Account.ClanID == player.AccountID)
                    {
                        mult += 0.5;                                                                           // owner's clan
                    }
                    if (planet.AccountPlanets.Any(x => x.AccountID == player.AccountID && x.DropshipCount > 0))
                    {
                        mult += 1;                                                                                         // own dropship
                    }
                    else if (planet.AccountPlanets.Any(x => x.DropshipCount > 0 && x.Account.ClanID == player.ClanID))
                    {
                        mult += 0.5;                                                                                                // clan's dropship
                    }
                    playerScoreMultiplier[i] = mult;

                    //res.Message += string.Format("{0} mult = {1} \n", players[i].Name, mult);
                }

                var    limit             = 1 << (players.Count);
                var    bestCombination   = -1;
                var    bestScore         = double.MinValue;
                double bestCompo         = 0;
                double absCompo          = 0;
                double bestElo           = 0;
                double bestTeamDiffs     = 0;
                var    playerAssignments = new int[players.Count];
                for (var combinator = 0; combinator < limit; combinator++)
                {
                    //double team0Weight = 0;
                    double team0Elo = 0;
                    //double team1Weight = 0;
                    double team1Elo   = 0;
                    var    team0count = 0;
                    var    team1count = 0;

                    // determine where each player is amd dp some adding
                    for (var i = 0; i < players.Count; i++)
                    {
                        var player = players[i];
                        var team   = (combinator & (1 << i)) > 0 ? 1 : 0;
                        playerAssignments[i] = team;
                        if (team == 0)
                        {
                            team0Elo += player.EffectiveElo;
                            //team0Weight += player.EloWeight;
                            team0count++;
                        }
                        else
                        {
                            team1Elo += player.EffectiveElo; // *player.EloWeight;
                            //team1Weight += player.EloWeight;
                            team1count++;
                        }
                    }
                    if (team0count == 0 || team1count == 0)
                    {
                        continue;                                     // skip combination, empty team
                    }
                    // calculate score for team difference
                    var teamDiffScore = -(20.0 * Math.Abs(team0count - team1count) / (double)(team0count + team1count)) -
                                        Math.Abs(team0count - team1count);
                    if (teamDiffScore < -10)
                    {
                        continue;                      // max imabalance
                    }
                    double balanceModifier = 0;
                    // count elo vs balance modifier

                    /*
                     * if (team0count < team1count) balanceModifier = -teamDiffScore;
                     * else balanceModifier = teamDiffScore;*/

                    // calculate score for elo difference

                    team0Elo = team0Elo / team0count;
                    team1Elo = team1Elo / team1count;
                    //team0Elo = team0Elo/team0Weight;
                    //team1Elo = team1Elo/team1Weight;
                    var eloScore = -Math.Abs(team0Elo - team1Elo) / 14;
                    if (eloScore < -17)
                    {
                        continue;
                    }

                    if (team0Elo < team1Elo)
                    {
                        balanceModifier += -eloScore;
                    }
                    else
                    {
                        balanceModifier += eloScore;
                    }

                    // verify if ther eis sense in playing (no zero sum game ip abuse)
                    var majorityFactions = (from teamData in Enumerable.Range(0, players.Count).GroupBy(x => playerAssignments[x])
                                            let majorityCount = Math.Ceiling(teamData.Count() / 2.0)
                                                                select
                                                                teamData.GroupBy(x => players[x].FactionID).Where(x => x.Key != null && x.Count() >= majorityCount).
                                                                Select(x => x.Key ?? 0)).ToList();
                    if (majorityFactions.Count == 2 && majorityFactions[0].Intersect(majorityFactions[1]).Any())
                    {
                        continue;                                                                                          // winning either side would be benefitial for some majority faction
                    }
                    // calculate score for meaningfull teams
                    var compoScore = 0.0;
                    for (var i = 0; i < players.Count; i++) // for every player calculate his score as average of relations to other plaeyrs
                    {
                        double sum = 0;
                        var    cnt = 0;
                        for (var j = 0; j < players.Count; j++)
                        {
                            if (i != j)
                            {
                                var sts = sameTeamScore[i, j];
                                if (sts != 0.0) // we only consider no-neutral people
                                {
                                    if (playerAssignments[i] == playerAssignments[j])
                                    {
                                        sum += sts;
                                        cnt++;
                                    }

                                    /*else sum -= sts; // different teams - score is equal to negation of same team score
                                     * cnt++;*/
                                }
                            }
                        }
                        if (cnt > 0) // player can be meaningfully ranked, he had at least one non zero relation
                        {
                            compoScore += playerScoreMultiplier[i] * sum / cnt;
                        }
                    }

                    if (compoScore < 0)
                    {
                        continue;                 // get meaningfull teams only   || compoScore < 0.5*absCompo
                    }
                    if (compoScore > absCompo)
                    {
                        absCompo = compoScore;                        // todo lame - abs compo not known at this point,should be 2 pass
                    }
                    var score = -Math.Abs(balanceModifier) + teamDiffScore + compoScore;

                    if (score > bestScore)
                    {
                        bestCombination = combinator;
                        bestScore       = score;
                        bestElo         = eloScore;
                        bestCompo       = compoScore;
                        bestTeamDiffs   = teamDiffScore;
                    }
                }

                if (bestCombination == -1)
                {
                    res.BalancedTeams = null;
                    res.Message      += "Cannot be balanced well at this point";
                }

                /*else if (bestCompo < absCompo*0.5)
                 * {
                 * res.BalancedTeams = null;
                 * res.Message += string.Format("Cannot be balanced well at this point - best composition: {0}, available: {1}", absCompo, bestCompo);
                 * }*/
                else
                {
                    var differs = false;
                    for (var i = 0; i < players.Count; i++)
                    {
                        var allyID = ((bestCombination & (1 << i)) > 0) ? 1 : 0;
                        if (!differs && allyID != currentTeams.First(x => x.AccountID == players[i].LobbyID).AllyID)
                        {
                            differs = true;
                        }
                        res.BalancedTeams.Add(new AccountTeam()
                        {
                            AccountID = players[i].LobbyID.Value, Name = players[i].Name, AllyID = allyID, TeamID = i
                        });
                    }
                    if (differs)
                    {
                        res.Message +=
                            string.Format(
                                "Winning combination  score: {0:0.##} team difference,  {1:0.##} elo,  {2:0.##} composition. Win chance {3}%",
                                bestTeamDiffs,
                                bestElo,
                                bestCompo,
                                Utils.GetWinChancePercent(bestElo * 20));
                    }
                }
                res.DeleteBots = true;
                return(res);
            }
        }
    }
        public static string SubmitSpringBattleResult(BattleContext context,
                                                      string password,
                                                      BattleResult result,
                                                      List <BattlePlayerResult> players,
                                                      List <string> extraData)
        {
            try
            {
                Account acc = AuthServiceClient.VerifyAccountPlain(context.AutohostName, password);
                if (acc == null)
                {
                    throw new Exception("Account name or password not valid");
                }
                AutohostMode mode = context.GetMode();
                var          db   = new ZkDataContext();

                if (extraData == null)
                {
                    extraData = new List <string>();
                }


                var sb = new SpringBattle
                {
                    HostAccountID  = acc.AccountID,
                    Duration       = result.Duration,
                    EngineGameID   = result.EngineBattleID,
                    MapResourceID  = db.Resources.Single(x => x.InternalName == result.Map).ResourceID,
                    ModResourceID  = db.Resources.Single(x => x.InternalName == result.Mod).ResourceID,
                    HasBots        = result.IsBots,
                    IsMission      = result.IsMission,
                    PlayerCount    = players.Count(x => !x.IsSpectator),
                    StartTime      = result.StartTime,
                    Title          = result.Title,
                    ReplayFileName = result.ReplayName,
                    EngineVersion  = result.EngineVersion,
                };
                db.SpringBattles.InsertOnSubmit(sb);

                foreach (BattlePlayerResult p in players)
                {
                    sb.SpringBattlePlayers.Add(new SpringBattlePlayer
                    {
                        AccountID       = db.Accounts.First(x => x.AccountID == p.LobbyID).AccountID,
                        AllyNumber      = p.AllyNumber,
                        CommanderType   = p.CommanderType,
                        IsInVictoryTeam = p.IsVictoryTeam,
                        IsSpectator     = p.IsSpectator,
                        LoseTime        = p.LoseTime
                    });
                }

                db.SubmitChanges();

                // awards
                foreach (string line in extraData.Where(x => x.StartsWith("award")))
                {
                    string[] partsSpace = line.Substring(6).Split(new[] { ' ' }, 3);
                    string   name       = partsSpace[0];
                    string   awardType  = partsSpace[1];
                    string   awardText  = partsSpace[2];

                    SpringBattlePlayer player = sb.SpringBattlePlayers.FirstOrDefault(x => x.Account.Name == name);
                    if (player != null)
                    {
                        db.AccountBattleAwards.InsertOnSubmit(new AccountBattleAward
                        {
                            AccountID        = player.AccountID,
                            SpringBattleID   = sb.SpringBattleID,
                            AwardKey         = awardType,
                            AwardDescription = awardText
                        });
                    }
                }

                var  text         = new StringBuilder();
                bool isPlanetwars = false;
                if (mode == AutohostMode.Planetwars && sb.SpringBattlePlayers.Count(x => !x.IsSpectator) >= 2 && sb.Duration >= GlobalConst.MinDurationForPlanetwars)
                {
                    // test that factions are not intermingled (each faction only has one ally number) - if they are it wasnt actually PW balanced
                    if (
                        sb.SpringBattlePlayers.Where(x => !x.IsSpectator && x.Account.Faction != null)
                        .GroupBy(x => x.Account.Faction)
                        .All(grp => grp.Select(x => x.AllyNumber).Distinct().Count() < 2))
                    {
                        isPlanetwars = true;


                        List <int> winnerTeams =
                            sb.SpringBattlePlayers.Where(x => x.IsInVictoryTeam && !x.IsSpectator).Select(x => x.AllyNumber).Distinct().ToList();
                        int?winNum = null;
                        if (winnerTeams.Count == 1)
                        {
                            winNum = winnerTeams[0];
                            if (winNum > 1)
                            {
                                winNum = null;
                                text.AppendLine("ERROR: Invalid winner");
                            }
                        }

                        PlanetWarsTurnHandler.EndTurn(result.Map, extraData, db, winNum, sb.SpringBattlePlayers.Where(x => !x.IsSpectator).Select(x => x.Account).ToList(), text, sb, sb.SpringBattlePlayers.Where(x => !x.IsSpectator && x.AllyNumber == 0).Select(x => x.Account).ToList());

                        Global.PlanetWarsMatchMaker.RemoveFromRunningBattles(context.AutohostName);
                    }
                    else
                    {
                        text.AppendLine("Battle wasn't PlanetWars balanced, it counts as a normal team game only");
                    }
                }

                bool noElo = (extraData.FirstOrDefault(x => x.StartsWith("noElo")) != null);
                try
                {
                    db.SubmitChanges();
                }
                catch (System.Data.Linq.DuplicateKeyException ex)
                {
                    Trace.TraceError(ex.ToString());
                }

                Dictionary <int, int> orgLevels = sb.SpringBattlePlayers.Select(x => x.Account).ToDictionary(x => x.AccountID, x => x.Level);

                sb.CalculateAllElo(noElo, isPlanetwars);
                foreach (var u in sb.SpringBattlePlayers.Where(x => !x.IsSpectator))
                {
                    u.Account.CheckLevelUp();
                }

                db.SubmitAndMergeChanges();

                try
                {
                    foreach (Account a in sb.SpringBattlePlayers.Where(x => !x.IsSpectator).Select(x => x.Account))
                    {
                        Global.Nightwatch.Tas.Extensions.PublishAccountData(a);
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("error updating extension data: {0}", ex);
                }

                foreach (Account account in sb.SpringBattlePlayers.Select(x => x.Account))
                {
                    if (account.Level > orgLevels[account.AccountID])
                    {
                        try
                        {
                            string message =
                                string.Format("Congratulations {0}! You just leveled up to level {1}. {3}/Users/Detail/{2}",
                                              account.Name,
                                              account.Level,
                                              account.AccountID,
                                              GlobalConst.BaseSiteUrl);
                            //text.AppendLine(message);
                            AuthServiceClient.SendLobbyMessage(account, message);
                        }
                        catch (Exception ex)
                        {
                            Trace.TraceError("Error sending level up lobby message: {0}", ex);
                        }
                    }
                }

                text.AppendLine(string.Format("BATTLE DETAILS AND REPLAY ----> {1}/Battles/Detail/{0} <-----", sb.SpringBattleID, GlobalConst.BaseSiteUrl));

                // create debriefing room, join players there and output message
                string channelName = "B" + sb.SpringBattleID;
                var    joinplayers = new List <string>();
                joinplayers.AddRange(context.Players.Select(x => x.Name));                                              // add those who were there at start
                joinplayers.AddRange(sb.SpringBattlePlayers.Select(x => x.Account.Name));                               // add those who played
                TasClient tas = Global.Nightwatch.Tas;
                Battle    bat = tas.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == context.AutohostName); // add those in lobby atm


                var conf = context.GetConfig();
                if (bat != null && (conf == null || conf.MinToJuggle == null)) // if not qm room do not join those who are in battle
                {
                    List <string> inbatPlayers = bat.Users.Keys.ToList();
                    joinplayers.RemoveAll(x => inbatPlayers.Contains(x));
                }
                foreach (string jp in joinplayers.Distinct().Where(x => x != context.AutohostName))
                {
                    tas.ForceJoinChannel(jp, channelName);
                }
                tas.JoinChannel(channelName); // join nightwatch and say it
                tas.Say(SayPlace.Channel, channelName, text.ToString(), true);
                tas.LeaveChannel(channelName);

                //text.Append(string.Format("Debriefing in #{0} - zk://chat/channel/{0}  ", channelName));
                return(text.ToString());
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                return(ex.ToString());
            }
        }