BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, BattleContext b, params List <Account>[] unmovablePlayers) { var ret = new BalanceTeamsResult(); try { ret.CanStart = true; ret.Players = b.Players.ToList(); var db = new ZkDataContext(); var nonSpecList = b.Players.Where(y => !y.IsSpectator).Select(y => (int?)y.LobbyID).ToList(); var accs = db.Accounts.Where(x => nonSpecList.Contains(x.AccountID)).ToList(); if (accs.Count < 1) { ret.CanStart = false; return(ret); } if (teamCount < 1) { teamCount = 1; } if (teamCount > accs.Count) { teamCount = accs.Count; } if (teamCount == 1) { foreach (var p in ret.Players) { p.AllyID = 0; } return(ret); } maxTeamSize = (int)Math.Ceiling(accs.Count / (double)teamCount); teams.Clear(); for (var i = 0; i < teamCount; i++) { var team = new BalanceTeam(); teams.Add(team); if (unmovablePlayers != null && unmovablePlayers.Length > i) { var unmovables = unmovablePlayers[i]; team.AddItem(new BalanceItem(unmovablePlayers[i].ToArray()) { CanBeMoved = false }); accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID)); } } balanceItems = new List <BalanceItem>(); if (mode == BalanceMode.ClanWise) { var clanGroups = accs.GroupBy(x => x.ClanID ?? x.AccountID).ToList(); if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) { mode = BalanceMode.Normal; } else { balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(x.ToArray()))); } } if (mode == BalanceMode.FactionWise) { balanceItems.Clear(); var factionGroups = accs.GroupBy(x => x.FactionID ?? x.AccountID).ToList(); balanceItems.AddRange(factionGroups.Select(x => new BalanceItem(x.ToArray()))); } if (mode == BalanceMode.Normal) { balanceItems.Clear(); balanceItems.AddRange(accs.Select(x => new BalanceItem(x))); } var sw = new Stopwatch(); sw.Start(); RecursiveBalance(0); sw.Stop(); if (bestTeams == null) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return(fallback); } var minSize = bestTeams.Min(x => x.Count); var maxSize = bestTeams.Max(x => x.Count); var sizesWrong = maxSize / (double)minSize > MaxTeamSizeDifferenceRatio; // cbalance failed, rebalance using normal if (mode == BalanceMode.ClanWise && (bestTeams == null || GetTeamsDifference(bestTeams) > MaxCbalanceDifference || sizesWrong)) { return(new Balancer().LegacyBalance(teamCount, BalanceMode.Normal, b, unmovablePlayers)); } // cbalance failed, rebalance using normal if (sizesWrong && mode == BalanceMode.FactionWise) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return(fallback); // fallback standard balance if PW balance fails /*ret.CanStart = false; * ret.Message = string.Format("Failed to balance - too many people from same faction"); * return ret;*/ } if (unmovablePlayers != null && unmovablePlayers.Length > 0) { var minElo = bestTeams.Min(x => x.AvgElo); var maxElo = bestTeams.Max(x => x.AvgElo); if (maxElo - minElo > GlobalConst.MaxPwEloDifference) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return(fallback); // fallback standard balance if PW balance fails /* * ret.CanStart = false; * ret.Message = string.Format("Team difference is too big - win chance {0}% - spectate some or wait for more people", * Utils.GetWinChancePercent(maxElo - minElo)); * return ret;*/ } } if (bestTeams == null) { ret.CanStart = false; ret.Message = string.Format( "Failed to balance {0} - too many people from same clan or faction (in teams game you can try !random and !forcestart)"); return(ret); } else { if (unmovablePlayers == null || unmovablePlayers.Length == 0) { bestTeams = bestTeams.Shuffle(); // permute when not unmovable players present } var text = "( "; var lastTeamElo = 0.0; var allyNum = 0; foreach (var team in bestTeams) { if (allyNum > 0) { text += " : "; } text += string.Format("{0}", (allyNum + 1)); if (allyNum > 0) { text += string.Format("={0}%)", Utils.GetWinChancePercent(lastTeamElo - team.AvgElo)); } lastTeamElo = team.AvgElo; foreach (var u in team.Items.SelectMany(x => x.LobbyId)) { ret.Players.Single(x => x.LobbyID == u).AllyID = allyNum; } allyNum++; } text += ")"; ret.Message = String.Format("{0} players balanced {2} to {1} teams {3}. {4} combinations checked, spent {5}ms of CPU time", bestTeams.Sum(x => x.Count), teamCount, mode, text, iterationsChecked, sw.ElapsedMilliseconds); } } catch (Exception ex) { Trace.TraceError(ex.ToString()); ret.Message = ex.ToString(); ret.CanStart = false; } return(ret); }
static BalanceTeamsResult PerformBalance(BattleContext context, bool isGameStart, int?allyCount, bool?clanWise, AutohostConfig config, int playerCount) { var res = new BalanceTeamsResult(); var mode = context.GetMode(); using (var db = new ZkDataContext()) { if (!CheckPlayersMinimumConditions(context, db, config, ref res.Message)) { res.CanStart = false; return(res); } switch (mode) { case AutohostMode.None: { if (!isGameStart) { res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context); } } break; case AutohostMode.Generic: { if (allyCount == null && res.Bots != null && res.Bots.Any()) { res.Players = context.Players.ToList(); res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList(); foreach (var p in res.Players) { p.AllyID = 0; } foreach (var b in res.Bots) { b.AllyID = 1; } } else { var map = db.Resources.Single(x => x.InternalName == context.Map); res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = mode == AutohostMode.Teams; } return(res); } case AutohostMode.Teams: { var map = db.Resources.Single(x => x.InternalName == context.Map); res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = mode == AutohostMode.Teams; return(res); } case AutohostMode.Game1v1: { res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = true; } break; case AutohostMode.GameChickens: { res.Players = context.Players.ToList(); res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList(); foreach (var p in res.Players) { p.AllyID = 0; } foreach (var b in res.Bots) { b.AllyID = 1; } if (!res.Bots.Any() && res.Players.Count > 0) { res.Message = "Add some bot (computer player) as your enemy. Use button on bottom left. Chicken or CAI is recommended."; res.CanStart = false; /*else * { * res.Bots.Add(new BotTeam() { AllyID = 1, TeamID = 16, BotName = "default_Chicken", BotAI = "Chicken: Normal", }); * res.Message = "Adding a normal chickens bot for you"; * }*/ } } break; case AutohostMode.GameFFA: { var map = db.Resources.Single(x => x.InternalName == context.Map); if (map.MapFFAMaxTeams != null) { res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams.Value, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } else { res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 8, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } return(res); } case AutohostMode.Planetwars: return(new Balancer().PlanetwarsBalance(context)); } return(res); } }
/// <summary> /// Calls <see cref="LegacyBalance" /> with the appropriate parameters depending on game settings and conditions /// </summary> /// <param name="isGameStart"> /// If true and <see cref="AutohostMode" /> is none, do nothing (i.e. don't autobalance custom /// rooms at start) /// </param> /// <param name="allyCount"></param> /// <param name="clanWise"></param> /// <param name="config"></param> /// <remarks>Also removes bots from team games, and tells people to add bots to a chicken game if absent</remarks> static BalanceTeamsResult PerformBalance( LobbyHostingContext context, bool isGameStart, int?allyCount, bool?clanWise) { var res = new BalanceTeamsResult(); var mode = context.Mode; using (var db = new ZkDataContext()) { switch (mode) { case AutohostMode.None: { if (!isGameStart) { if (allyCount == null || allyCount == 2) { res = PartitionBalance.BalanceInterface(2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } else { res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context); } } } break; case AutohostMode.Teams: case AutohostMode.Game1v1: { res = PartitionBalance.BalanceInterface(2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = true; } break; case AutohostMode.GameChickens: { res.Players = context.Players.ToList(); res.Bots = context.Bots.ToList(); foreach (var p in res.Players) { p.AllyID = 0; } foreach (var b in res.Bots) { b.AllyID = 1; } // add chickens via modoptions hackish thingie string chickBot = null; if (context.ModOptions?.TryGetValue("chickenailevel", out chickBot) == true && !string.IsNullOrEmpty(chickBot) && chickBot != "none") { res.Bots.RemoveAll(x => x.BotAI.StartsWith("Chicken:")); res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "default_Chicken", BotAI = chickBot }); } if (!res.Bots.Any() && res.Players.Count > 0) { //res.Message = "Add some bot (computer player) as your enemy. Use button on bottom left. Chicken or CAI is recommended."; var map = db.Resources.FirstOrDefault(x => x.InternalName == context.Map); if (map?.MapIsChickens == true) { res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "default_Chicken", BotAI = "Chicken: Normal", }); } else { for (int i = 1; i <= res.Players.Where(x => !x.IsSpectator).Count(); i++) { res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "cai" + i, BotAI = "CAI", }); } } res.Message = "Adding computer AI player for you"; } } break; case AutohostMode.GameFFA: { res.DeleteBots = true; var map = db.Resources.Single(x => x.InternalName == context.Map); if (map.MapFFAMaxTeams != null) { res = new Balancer().LegacyBalance( allyCount ?? map.MapFFAMaxTeams.Value, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } else { res = new Balancer().LegacyBalance( allyCount ?? map.MapFFAMaxTeams ?? 8, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } return(res); } case AutohostMode.Planetwars: return(new Balancer().PlanetwarsBalance(context)); } return(res); } }
/// <summary> /// The function that actually moves players arounds /// </summary> /// <param name="teamCount"></param> /// <param name="mode"></param> /// <param name="b"></param> /// <param name="unmovablePlayers"></param> /// <returns></returns> BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, LobbyHostingContext b, params List<Account>[] unmovablePlayers) { var ret = new BalanceTeamsResult(); if (b.IsMatchMakerGame) mode = BalanceMode.Party; // override, for matchmaker mode is always party try { ret.CanStart = true; ret.Players = b.Players.ToList(); var db = new ZkDataContext(); var nonSpecList = b.Players.Where(y => !y.IsSpectator).Select(y => (int?)y.LobbyID).ToList(); var accs = db.Accounts.Where(x => nonSpecList.Contains(x.AccountID)).ToList(); if (accs.Count < 1) { ret.CanStart = false; return ret; } if (teamCount < 1) teamCount = 1; if (teamCount > accs.Count) teamCount = accs.Count; if (teamCount == 1) { foreach (var p in ret.Players) p.AllyID = 0; return ret; } maxTeamSize = (int)Math.Ceiling(accs.Count / (double)teamCount); teams.Clear(); for (var i = 0; i < teamCount; i++) { var team = new BalanceTeam(); teams.Add(team); if (unmovablePlayers != null && unmovablePlayers.Length > i) { var unmovables = unmovablePlayers[i]; team.AddItem(new BalanceItem(b.IsMatchMakerGame, unmovablePlayers[i].ToArray()) { CanBeMoved = false }); accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID)); } } balanceItems = new List<BalanceItem>(); if (mode == BalanceMode.Party) { var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? x.AccountID).ToList(); if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) mode = BalanceMode.Normal; else balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray()))); } if (mode == BalanceMode.ClanWise) { var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? x.ClanID ?? x.AccountID).ToList(); if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) mode = BalanceMode.Normal; else balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray()))); } if (mode == BalanceMode.FactionWise) { balanceItems.Clear(); var factionGroups = accs.GroupBy(x => x.FactionID ?? x.AccountID).ToList(); balanceItems.AddRange(factionGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray()))); } if (mode == BalanceMode.Normal) { balanceItems.Clear(); balanceItems.AddRange(accs.Select(x => new BalanceItem(b.IsMatchMakerGame, x))); } var sw = new Stopwatch(); sw.Start(); RecursiveBalance(0); sw.Stop(); if (bestTeams == null) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return fallback; } var minSize = bestTeams.Min(x => x.Count); var maxSize = bestTeams.Max(x => x.Count); var sizesWrong = maxSize / (double)minSize > MaxTeamSizeDifferenceRatio; // cbalance failed, rebalance using normal if (mode == BalanceMode.ClanWise && (bestTeams == null || GetTeamsDifference(bestTeams) > MaxCbalanceDifference || sizesWrong)) return new Balancer().LegacyBalance(teamCount, BalanceMode.Normal, b, unmovablePlayers); // cbalance failed, rebalance using normal if (sizesWrong && mode == BalanceMode.FactionWise) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return fallback; // fallback standard balance if PW balance fails /*ret.CanStart = false; ret.Message = string.Format("Failed to balance - too many people from same faction"); return ret;*/ } if (unmovablePlayers != null && unmovablePlayers.Length > 0) { var minElo = bestTeams.Min(x => x.AvgElo); var maxElo = bestTeams.Max(x => x.AvgElo); if (maxElo - minElo > GlobalConst.MaxPwEloDifference) { var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null); fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction"; return fallback; // fallback standard balance if PW balance fails /* ret.CanStart = false; ret.Message = string.Format("Team difference is too big - win chance {0}% - spectate some or wait for more people", Utils.GetWinChancePercent(maxElo - minElo)); return ret;*/ } } if (bestTeams == null) { ret.CanStart = false; ret.Message = string.Format( "Failed to balance {0} - too many people from same clan or faction (in teams game you can try !random and !forcestart)"); return ret; } if (unmovablePlayers == null || unmovablePlayers.Length == 0) bestTeams = bestTeams.Shuffle(); // permute when not unmovable players present var text = "( "; var lastTeamElo = 0.0; var allyNum = 0; foreach (var team in bestTeams) { if (allyNum > 0) text += " : "; text += string.Format("{0}", (allyNum + 1)); if (allyNum > 0) text += string.Format("={0}%)", Utils.GetWinChancePercent(lastTeamElo - team.AvgElo)); lastTeamElo = team.AvgElo; foreach (var u in team.Items.SelectMany(x => x.LobbyId)) ret.Players.Single(x => x.LobbyID == u).AllyID = allyNum; allyNum++; } text += ")"; ret.Message = string.Format( "{0} players balanced {2} to {1} teams {3}. {4} combinations checked, spent {5}ms of CPU time", bestTeams.Sum(x => x.Count), teamCount, mode, text, iterationsChecked, sw.ElapsedMilliseconds); } catch (Exception ex) { Trace.TraceError(ex.ToString()); ret.Message = ex.ToString(); ret.CanStart = false; } return ret; }
/// <summary> /// Calls <see cref="LegacyBalance" /> with the appropriate parameters depending on game settings and conditions /// </summary> /// <param name="isGameStart"> /// If true and <see cref="AutohostMode" /> is none, do nothing (i.e. don't autobalance custom /// rooms at start) /// </param> /// <param name="allyCount"></param> /// <param name="clanWise"></param> /// <param name="config"></param> /// <remarks>Also removes bots from team games, and tells people to add bots to a chicken game if absent</remarks> static BalanceTeamsResult PerformBalance( LobbyHostingContext context, bool isGameStart, int? allyCount, bool? clanWise) { var res = new BalanceTeamsResult(); var mode = context.Mode; using (var db = new ZkDataContext()) { switch (mode) { case AutohostMode.None: { if (!isGameStart) res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context); } break; case AutohostMode.Teams: case AutohostMode.Game1v1: { res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = true; } break; case AutohostMode.GameChickens: { res.Players = context.Players.ToList(); res.Bots = context.Bots.ToList(); foreach (var p in res.Players) p.AllyID = 0; foreach (var b in res.Bots) b.AllyID = 1; // add chickens via modoptions hackish thingie string chickBot = null; if (context.ModOptions?.TryGetValue("chickenailevel", out chickBot) == true && !string.IsNullOrEmpty(chickBot) && chickBot != "none") { res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "default_Chicken", BotAI = chickBot }); } if (!res.Bots.Any() && res.Players.Count > 0) { //res.Message = "Add some bot (computer player) as your enemy. Use button on bottom left. Chicken or CAI is recommended."; var map = db.Resources.FirstOrDefault(x => x.InternalName == context.Map); if (map?.MapIsChickens == true) res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "default_Chicken", BotAI = "Chicken: Normal", }); else res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "cai", BotAI = "CAI", }); res.Message = "Adding computer AI player for you"; } } break; case AutohostMode.GameFFA: { res.DeleteBots = true; var map = db.Resources.Single(x => x.InternalName == context.Map); if (map.MapFFAMaxTeams != null) { res = new Balancer().LegacyBalance( allyCount ?? map.MapFFAMaxTeams.Value, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } else { res = new Balancer().LegacyBalance( allyCount ?? map.MapFFAMaxTeams ?? 8, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); } return res; } case AutohostMode.Planetwars: return new Balancer().PlanetwarsBalance(context); } return res; } }
static BalanceTeamsResult PerformBalance(BattleContext context, bool isGameStart, int? allyCount, bool? clanWise, AutohostConfig config, int playerCount) { var res = new BalanceTeamsResult(); var mode = context.GetMode(); using (var db = new ZkDataContext()) { if (!CheckPlayersMinimumConditions(context, db, config, ref res.Message)) { res.CanStart = false; return res; } switch (mode) { case AutohostMode.None: { if (!isGameStart) res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context); } break; case AutohostMode.Generic: { if (allyCount == null && res.Bots != null && res.Bots.Any()) { res.Players = context.Players.ToList(); res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList(); foreach (var p in res.Players) p.AllyID = 0; foreach (var b in res.Bots) b.AllyID = 1; } else { var map = db.Resources.Single(x => x.InternalName == context.Map); res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = mode == AutohostMode.Teams; } return res; } case AutohostMode.Teams: { var map = db.Resources.Single(x => x.InternalName == context.Map); res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = mode == AutohostMode.Teams; return res; } case AutohostMode.Game1v1: { res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); res.DeleteBots = true; } break; case AutohostMode.GameChickens: { res.Players = context.Players.ToList(); res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList(); foreach (var p in res.Players) p.AllyID = 0; foreach (var b in res.Bots) b.AllyID = 1; if (!res.Bots.Any() && res.Players.Count > 0) { res.Message = "Add some bot (computer player) as your enemy. Use button on bottom left. Chicken or CAI is recommended."; res.CanStart = false; /*else { res.Bots.Add(new BotTeam() { AllyID = 1, TeamID = 16, BotName = "default_Chicken", BotAI = "Chicken: Normal", }); res.Message = "Adding a normal chickens bot for you"; }*/ } } break; case AutohostMode.GameFFA: { var map = db.Resources.Single(x => x.InternalName == context.Map); if (map.MapFFAMaxTeams != null) res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams.Value, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); else res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 8, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context); return res; } case AutohostMode.Planetwars: return new Balancer().PlanetwarsBalance(context); } return res; } }
static bool listOnlyThatLevelsModules = false; // may cause bugs /// <summary> /// Sets up all the things that Springie needs to know for the battle: how to balance, who to get extra commanders, what PlanetWars structures to create, etc. /// </summary> 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(); // calculate to whom to send extra comms var accountIDsWithExtraComms = new List <int>(); if (mode == AutohostMode.Planetwars || mode == AutohostMode.Generic || mode == AutohostMode.GameFFA || mode == AutohostMode.Teams) { 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.AccountID == 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; // write Planetwars details to modoptions (for widget) 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.AccountID == 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 }); } // write player custom keys (level, elo, is muted, etc.) foreach (PlayerTeam p in context.Players) { Account user = db.Accounts.Find(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 }); userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "admin", Value = (user.IsZeroKAdmin ? "1" : "0") }); if (!p.IsSpectator) { // set valid PW structure attackers 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) { // set up commander data 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() }); // set PW structures 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; } }