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 = db.Accounts.Find(accountID); // accountID is in fact lobbyID if (account != null) { var config = context.GetConfig(); if (account.Level < config.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.", config.MinLevel); res.ForceSpec = true; 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} {6}/PlanetWars/Planet/{5}", account.Name, facRoles, clanRoles, owner, planet.Name, planet.PlanetID, GlobalConst.BaseSiteUrl); return(res); } } Account acc = db.Accounts.Find(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); }
/// <summary> /// Picks a map and writes a message if applicable /// </summary> /// <param name="context">The battle whose map needs selection</param> /// <param name="pickNew">If false and not in PlanetWars, don't pick a new map</param> /// <remarks> /// <para>For Planetwars, picks the map given by the Planetwars matchmaker; else picks a featured map with the appropriate tags</para> /// <para>For team and chickens games, picks a map of appropriate size based on current player count</para> /// <para>For FFA, prefer maps that have a number of boxes equal to player count, or at least a number of boxes that is a multiple of player count</para> /// </remarks> public static RecommendedMapResult GetRecommendedMap(BattleContext context, bool pickNew) { var mode = context.GetMode(); var config = context.GetConfig(); var res = new RecommendedMapResult(); using (var db = new ZkDataContext()) { if (mode == AutohostMode.Planetwars) { var info = Global.PlanetWarsMatchMaker.GetBattleInfo(context.AutohostName); if (info != null) { res.MapName = info.Map; res.Message = String.Format("Welcome to planet {0} {2}/PlanetWars/Planet/{1} attacked", info.Name, info.PlanetID, GlobalConst.BaseSiteUrl); } else { res.MapName = context.Map; } } else { if (!pickNew) { // autohost is not managed or has valid featured map - check disabled res.MapName = context.Map; return(res); } List <Resource> list = null; var players = context.Players.Count(x => !x.IsSpectator); if (config != null && config.SplitBiggerThan != null && players > config.SplitBiggerThan) { players = players / 2; // expect the split } switch (mode) { case AutohostMode.Generic: case AutohostMode.Teams: case AutohostMode.None: var ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsTeams != false && x.MapIsSpecial != true); if (players > 11) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16); } else if (players > 8) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16 && (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24); } else if (players > 5) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true); } else { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 16 * 16 || x.MapIs1v1 == true); } list = ret.ToList(); break; case AutohostMode.Game1v1: list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIs1v1 == true && x.MapIsSpecial != true).ToList(); break; case AutohostMode.GameChickens: ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsSpecial != true && (x.MapIsChickens == true || x.MapWaterLevel == 1)); if (players > 5) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16); } else if (players > 4) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16 && (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24); } else if (players > 2) { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true); } else { ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 16 * 16 || x.MapIs1v1 == true); } list = ret.ToList(); break; case AutohostMode.GameFFA: list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && x.MapFFAMaxTeams == players).ToList(); if (!list.Any()) { list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && (players % x.MapFFAMaxTeams == 0)).ToList(); } if (!list.Any()) { list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true).ToList(); } break; } if (list != null) { var r = new Random(); if (list.Count > 0) { res.MapName = list[r.Next(list.Count)].InternalName; } } } } return(res); }
public static BalanceTeamsResult BalanceTeams(BattleContext context, bool isGameStart, int?allyCount, bool?clanWise) { var config = context.GetConfig(); var playerCount = context.Players.Count(x => !x.IsSpectator); // game is managed, is bigger than split limit and wants to start -> split into two and issue starts if (isGameStart && context.GetMode() != AutohostMode.None && config.SplitBiggerThan != null && config.SplitBiggerThan < playerCount) { new Thread(() => { try { SplitAutohost(context, true); } catch (Exception ex) { Trace.TraceError("Error when splitting game:{0}", ex); } }).Start(); return(new BalanceTeamsResult { CanStart = false, Message = string.Format("Game too big - splitting into two - max players is {0} here", config.SplitBiggerThan) }); } if (clanWise == null && (config.AutohostMode == AutohostMode.Generic || config.AutohostMode == AutohostMode.Teams)) { clanWise = true; } var res = PerformBalance(context, isGameStart, allyCount, clanWise, config, playerCount); if (context.GetMode() != AutohostMode.Planetwars) // planetwars skip other checks { if (isGameStart) { if (playerCount < (config.MinToStart ?? 0)) { res.Message = string.Format("This host needs at least {0} people to start", config.MinToStart); res.CanStart = false; return(res); } if (playerCount > (config.MaxToStart ?? 99)) { res.Message = string.Format("This host can only start with at most {0} players", config.MaxToStart); res.CanStart = false; return(res); } // dont allow to start alone if (playerCount <= 1) { if (res.DeleteBots) { return new BalanceTeamsResult { CanStart = false, Message = "You cannot play alone on this host, wait for players or join another game room and play with bots." } } ; if (!context.Bots.Any()) { return new BalanceTeamsResult { CanStart = false, Message = "Cannot play alone, you can add bots using button on bottom left." } } ; } } } if (isGameStart) { VerifySpecCheaters(context, res); } 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()); } }