using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TELTest.Matchmaking; namespace TELTest { public abstract class QuizGamemode { public static List Registry { get; } = new List() { new Gamemodes.Classic(), new Gamemodes.ClassicMP(), new Gamemodes.Kbmio(), new Gamemodes.Pisania(), new Gamemodes.Comments(), //new Gamemodes.Turns() }; protected QuizGamemode() { } protected QuizGamemode(QuizContainer container, BaseQuizContext context) { this.Quiz = container; this.Context = context; } public QuizContainer Quiz { get; protected set; } public BaseQuizContext Context { get; protected set; } public abstract QuizGamemode CreateInstance(QuizContainer quiz, BaseQuizContext context); public QuizGamemode CreateCheckInstance(QuizContainer quiz, BaseQuizContext context) { var inst = CreateInstance(quiz, context); if (inst.GetType() != this.GetType()) throw new InvalidOperationException("Sanity check: QuizGamemode.CreateInstance should return the current type, it returned " + inst.GetType() + " instead of " + this.GetType() + "."); return inst; } public abstract string Name { get; } public abstract string SystemName { get; } public abstract string Description { get; } protected const string SYSTEMNAME_WHITELIST = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; public abstract Task Begin(); public void JoinExistingLobby(Lobby lobby) { m_JoinMe = lobby; } private Lobby m_JoinMe = null; protected bool ValidateSystemName() { if (string.IsNullOrWhiteSpace(Name)) return false; for (int i = 0; i < SystemName.Length; i++) { if (!SYSTEMNAME_WHITELIST.Contains(SystemName[i])) return false; } return true; } public virtual async Task CreateJoinLobbyStandard() { await GUIUtilities.AskUsernameIfNeeded(Context.Handler, Context.Stream); Lobby lobby = null; if (m_JoinMe == null) { lobby = MatchmakingStuff.RequestNew(Quiz, this); lobby.Players.Add(this.Context.Handler); await GUIUtilities.LobbySettings(this.Context.Handler, this.Context.Stream, lobby); } else { lobby = m_JoinMe; lobby.Players.Add(this.Context.Handler); m_JoinMe = null; } bool aw = await GUIUtilities.LobbyAwait(this.Context.Handler, this.Context.Stream, lobby); if (!aw) { lobby.Players.Remove(Context.Handler); return null; } //MakePlayersUnready(lobby); return lobby; } const string SPINNER = "|/-\\"; public virtual async Task WaitForPlayersReady(Lobby lobby, bool clearScreen = false) { //lobby.Players.Where(x => x == Context.Handler).First().PlayerReady = true; Context.Handler.PlayerReady = true; int spinstage = 0; if (clearScreen) { await Clear(); await WriteLine(); } while (true) { bool allready = true; for (int i = 0; i < lobby.Players.Count; i++) { allready &= lobby.Players[i].PlayerReady; } await Write("\r " + SPINNER[spinstage] + " Czekanie na reszte graczy... " + SPINNER[spinstage] + " "); await Task.Delay(150); spinstage++; if (spinstage >= SPINNER.Length) spinstage = 0; if (allready) break; } await WriteLine(); await Task.Delay(300); } public void MakePlayersUnready(Lobby lobby) { for (int i = 0; i < lobby.Players.Count; i++) { lobby.Players[i].PlayerReady = false; } } public virtual async Task DoScoreSubmission(int score, bool _reserved = false) { if (!ValidateSystemName()) throw new InvalidOperationException("The system name of the gamemode is null, empty, exclusively whitespace, or contains invalid characters. Valid characters are \"" + SYSTEMNAME_WHITELIST + "\" (without quotes)."); Context.Handler.Flush(Context.Stream); var scoreboard = Scoreboard.Of(Quiz.Guid + "_" + SystemName); await Clear(); string nic = ""; if (!string.IsNullOrWhiteSpace(Context.Handler.PlayerName)) { if (await Context.Handler.Choice(Context.Stream, new[] { 'Y', 'N' }, "Zapisac wynik?", def: 'Y') == 'Y') { nic = Context.Handler.PlayerName; scoreboard.Add(new Scoreboard.ScoreboardEntry(nic, score)); } } else { await Write(Localization.UI["SAVESCORE"] + " "); nic = await Context.Handler.Read(Context.Stream, new ReadConfiguration() { Echo = true, Terminator = '\n', FlushAfterReading = true, MaxLength = 30, Whitelist = SYSTEMNAME_WHITELIST }); nic = nic.TrimEnd('\r', '\n').Trim(); if (!string.IsNullOrWhiteSpace(nic)) { scoreboard.Add(new Scoreboard.ScoreboardEntry(nic, score)); Context.Handler.PlayerName = nic; } } await Clear(); StringBuilder sb = new StringBuilder(); var high = scoreboard.Highscore(); bool hadScore = false; for (Int32 i = 0; i < high.Length; i++) { Scoreboard.ScoreboardEntry item = high[i]; bool current = item.Name == nic; hadScore |= current; sb.AppendLineRN(((i + 1).ToString().PadLeft(2) + ". " + (current? "-> " : " ") + item.Name).PadRight(38) + " " + item.Value); } if (!string.IsNullOrWhiteSpace(nic) && !hadScore) { for (Int32 i = 0; i < scoreboard.Entries.Count; i++) { var item = scoreboard.Entries[i]; if (item.Name == nic) { sb.AppendLineRN(); bool current = true; sb.AppendLineRN((i.ToString().PadLeft(2) + ". " + (current ? "->" : "") + item.Name).PadRight(38) + " " + item.Value); } } } sb.AppendLineRN(); await WriteLine(sb.ToString()); await Pause(); } public Task EndMP(Lobby lobby) { lobby.Players.Remove(Context.Handler); if (lobby.Players.Count == 0 && !lobby.AnnouncePublic) { lock (MatchmakingStuff.AllLobbies) MatchmakingStuff.AllLobbies.Remove(lobby); } Context.Handler.PlayerReady = false; return Task.FromResult(true); } public Task Flush() { Context.Handler.Flush(Context.Stream); return Task.FromResult(true); } public async Task Clear() { await Context.Handler.TryClear(Context.Stream); } public async Task Pause() { await Write(Localization.UI["ANYKEYCONTINUE"]); await ReadKey(false); await Flush(); await WriteLine(); } public async Task WriteLine() => await WriteLine(""); public async Task WriteLine(object format, params object[] args) { await Write(format + "\r\n", args); } public async Task Write(object format, params object[] args) { await Context.Handler.WriteASCII(Context.Stream, string.Format(format.ToString(), args)); } public async Task ReadLine() => await ReadLine(true); public async Task ReadLine(bool echo) { string rl = await Context.Handler.Read(Context.Stream, '\n', echo); return rl.TrimEnd('\r', '\n'); } public async Task ReadUppercaseKey() { char c = char.ToUpper(await ReadKey(false)); await Write(c); return c; } public async Task ReadKey() => await ReadKey(true); public async Task ReadKey(bool echo) { return await Context.Handler.ReadChar(Context.Stream, echo); } } }