diff --git a/Server/HnSRandom.cs b/Server/HnSRandom.cs new file mode 100644 index 0000000..e46591d --- /dev/null +++ b/Server/HnSRandom.cs @@ -0,0 +1,104 @@ +using Shared.Packet.Packets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Server +{ + public static class HnSRandom + { + public static Server server; + public static List selectedPlayers = new List(); + /// + /// Function for private server hosts to start a random game of Hide & Seek + /// + /// Integer expected for number of seekers + /// Returns a string with the selected stage and seekers to display in the console + public static string StartRandomGame(string arg) + { + string stage = RandomStage(); + int num = 0; + try { num = int.Parse(arg); } // checks if arg is a valid integer, if not return that the number is invalid + catch { return "Invalid number"; } + if (num > server.Clients.Count) + return "Number is higher than the amount of players"; + else if (num == server.Clients.Count) + return "Please have at least one hider available"; + int spacesLeft = server.Clients.Count - selectedPlayers.Count; // checks how many players have currently been unselected. + server.Logger.Warn(spacesLeft.ToString()); + if (spacesLeft < num) // If spaces left is lower than the number of seekers wanted then the selectedPlayers list gets cleared + selectedPlayers.Clear(); + List players = new List(); + for (int i = 0; i < num; i++) + { + string n = RandomPlayer(); + if (players.Contains(n) || selectedPlayers.Contains(n)) { i--; continue; } // if either list players or selectedPlayers contain the currently selected player, then redo the randomisation (if something happens where selectedPlayers doesnt get cleared this may cause an infinite loop) + players.Add(n); + selectedPlayers.Add(n); + } + foreach (Client client in server.Clients) + { + +#pragma warning disable CS4014 + client.Send(new ChangeStagePacket + { + Stage = stage, + Scenario = -1, + }); +#pragma warning restore CS4014 + } + string play = string.Join(',', players); + return $"Starting Random Game on {stage} with seeker(s): {play}"; + } + /// + /// Selects a stage based on a list in Settings + /// + /// Returns a string of a random stage + private static string RandomStage() + { + Random r = new Random(); + + List stageNames = new List(); + foreach (var stage in Settings.Instance.StageSelection) + { + if (stage.enabled == true) + stageNames.Add(stage.stageName); + } + int i = r.Next(0, stageNames.Count); + try + { + return stageNames[i]; + } + catch (IndexOutOfRangeException ex) + { + server.Logger.Warn("Something has gone wrong"); + return stageNames[i - 1]; + } + } + /// + /// Selects a random player currently connected to the server + /// + /// + private static string RandomPlayer() + { + Random r = new Random(); + int i = r.Next(0, server.Clients.Count); + try + { + return server.Clients[i].Name; + } + catch + { + return server.Clients[i - 1].Name; + } + } + + public static string DebugMessage() + { + string s = string.Join(',', selectedPlayers); + return $"Currently selected players: {s}"; + } + } +} \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index 1488638..98f86da 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -14,6 +14,7 @@ bool restartRequested = false; Logger consoleLogger = new Logger("Console"); DiscordBot bot = new DiscordBot(); +HnSRandom.server = server; await bot.Run(); async Task PersistShines() @@ -446,6 +447,14 @@ await c.Send(new ChangeStagePacket { return $"Sent players to {stage}:{-1}"; }); +CommandHandler.RegisterCommand("randomgame", args => +{ + const string optionUsage = "Usage: randomgame "; + if (args.Length < 1) + { return optionUsage; } + return HnSRandom.StartRandomGame(args[0]); +}); + CommandHandler.RegisterCommand("scenario", args => { const string optionUsage = "Valid options: merge [true/false]"; if (args.Length < 1) diff --git a/Server/Settings.cs b/Server/Settings.cs index 5b9ef16..ab4a108 100644 --- a/Server/Settings.cs +++ b/Server/Settings.cs @@ -21,7 +21,9 @@ public static void LoadSettings() { try { Instance = JsonConvert.DeserializeObject(text, new StringEnumConverter(new CamelCaseNamingStrategy())) ?? Instance; Logger.Info("Loaded settings from settings.json"); - } + if (Instance.StageSelection == null || Instance.StageSelection.Count < 1) + Instance.StageSelection = StageSelectionTable.Preset(); + } catch (Exception e) { Logger.Warn($"Failed to load settings.json: {e}"); } @@ -44,6 +46,7 @@ public static void SaveSettings(bool silent = false) { public FlipTable Flip { get; set; } = new FlipTable(); public ScenarioTable Scenario { get; set; } = new ScenarioTable(); public BanListTable BanList { get; set; } = new BanListTable(); + public List StageSelection { get; set; } = new List(); public DiscordTable Discord { get; set; } = new DiscordTable(); public ShineTable Shines { get; set; } = new ShineTable(); public PersistShinesTable PersistShines { get; set; } = new PersistShinesTable(); @@ -67,7 +70,41 @@ public class BanListTable { public ISet GameModes { get; set; } = new SortedSet(); } - public class FlipTable { + public class StageSelectionTable + { + public string stageName { get; set; } + public bool enabled { get; set; } = true; + public StageSelectionTable(string name) + { + stageName = name; + } + public static List Preset() + { + List list = new List + { + new StageSelectionTable("CapWorldHomeStage"), + new StageSelectionTable("WaterfallWorldHomeStage"), + new StageSelectionTable("SandWorldHomeStage"), + new StageSelectionTable("LakeWorldHomeStage"), + new StageSelectionTable("ForestWorldHomeStage"), + new StageSelectionTable("CloudWorldHomeStage") { enabled = false }, + new StageSelectionTable("ClashWorldHomeStage"), + new StageSelectionTable("CityWorldHomeStage"), + new StageSelectionTable("SnowWorldHomeStage"), + new StageSelectionTable("SeaWorldHomeStage"), + new StageSelectionTable("LavaWorldHomeStage"), + new StageSelectionTable("BossRaidWorldHomeStage") { enabled = false }, + new StageSelectionTable("SkyWorldHomeStage"), + new StageSelectionTable("MoonWorldHomeStage"), + new StageSelectionTable("PeachWorldHomeStage"), + new StageSelectionTable("Special1WorldHomeStage") { enabled = false }, + new StageSelectionTable("Special2WorldHomeStage") { enabled = false }, + }; + return list; + } + } + + public class FlipTable { public bool Enabled { get; set; } = true; public ISet Players { get; set; } = new SortedSet(); public FlipOptions Pov { get; set; } = FlipOptions.Both;