public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { List<JSONObject> outputs = new List<JSONObject>(); ModuleJSONObject moduleOutput; switch(command.Command) { case "me": moduleOutput = new ModuleJSONObject(); moduleOutput.broadcast = true; moduleOutput.message = user.Username + " " + command.Arguments[0]; //System.Security.SecurityElement.Escape(command.Arguments[0]); moduleOutput.tag = command.tag; outputs.Add(moduleOutput); break; case "emotes": moduleOutput = new ModuleJSONObject(); moduleOutput.message = "Emote list:\n"; try { string htmlCode; using (WebClient client = new WebClient()) { htmlCode = client.DownloadString(GetOption<string>("emoteLink")); } EmoteJSONObject emotes = JsonConvert.DeserializeObject<EmoteJSONObject>(htmlCode); foreach(string emote in emotes.mapping.Keys) moduleOutput.message += "\n" + emotes.format.Replace("emote", emote); } catch (Exception e) { moduleOutput.message = "Sorry, could not retrieve emote list!\nException: " + e.ToString(); } outputs.Add(moduleOutput); break; } return outputs; }
public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { List<JSONObject> outputs = new List<JSONObject>(); ModuleJSONObject output = new ModuleJSONObject(); string error = ""; switch (command.Command) { case "pm": //First, make sure this even works UserInfo recipient; output = new ModuleJSONObject(); if (!GetUserFromArgument(command.Arguments[0], users.Where(x => x.Value.LoggedIn).ToDictionary(x => x.Key, y => y.Value), out recipient)) { AddError(outputs); break; } output.tag = "any"; output.message = user.Username + " -> " + command.Arguments[0] + ":\n" + command.Arguments[1]; //System.Security.SecurityElement.Escape(command.Arguments[1]); output.recipients.Add(recipient.UID); output.recipients.Add(command.uid); outputs.Add(output); break; case "pmcreateroom": HashSet<int> roomUsers = new HashSet<int>(); foreach (string roomUser in command.ArgumentParts[0]) { UserInfo tempUser; if (!GetUserFromArgument(roomUser, users, out tempUser)) { error = "User not found!"; break; } else if (!roomUsers.Add(tempUser.UID)) { error = "Duplicate user in list: " + tempUser.Username; break; } } roomUsers.Add(user.UID); if (!string.IsNullOrWhiteSpace(error) || !ChatRunner.Server.CreatePMRoom(roomUsers, user.UID, out error)) { WarningJSONObject warning = new WarningJSONObject(error); outputs.Add(warning); } else { output.message = "You created a chatroom for " + string.Join(", ", roomUsers.Select(x => users[x].Username)); outputs.Add(output); } break; case "pmleaveroom": if (!ChatRunner.Server.LeavePMRoom(user.UID, command.tag, out error)) { WarningJSONObject warning = new WarningJSONObject(error); outputs.Add(warning); } else { output.message = "You left this PM room"; outputs.Add(output); } break; } return outputs; }
//THIS is the function you're looking for. When the chat server detects a command for your module, it passes it along //to this function. You can process the command here, then send the output as the return object. Notice that the return //is a list; you can return multiple messages per command. This function is called ONCE for each command detected. //"user" is the user who performed the command; the class UserInfo contains a lot of information about a user, so //use it as needed. The provided dictionary is a list of ALL users ever seen by the chat, so it's like the chat server's //database. Each UserInfo object has a "LoggedIn" field, so you can tell if they're logged in or not. "command" has //two important fields: "Command" and "Arguments". Command is simply the string containing just the command performed, //and Arguments is a list (array) of the arguments, each as a string. The returned messages are in a JSON format, which //is masked by the JSONObject class. You will almost ALWAYS be returning one or more ModuleJSONObjects, which is a //chat server message specific to modules. You can also return system messages, etc. All the X_JSONObjects classes like //ModuleJSONObject derive from the JSONObject class, so you can return any of them. The "message" field of the //ModuleJSONObject holds the output, and you can change the recipient by adding users (as integers) to the "recipients" //field. If you do not specify any recipients, it defaults to the sender (this is usually what you want). If you //want to broadcast a message to everyone (please don't do this for every command), you can set the "broadcast" field //to true. public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { //This is what we're returning from our function List<JSONObject> outputs = new List<JSONObject>(); //Our commands (and probably yours too) usually returns just one message, so that's what this is. //It gets added to the above "outputs" list. ModuleJSONObject moduleOutput = new ModuleJSONObject(); List<UserStatistics> allStats = userStatistics.Select(x => x.Value).ToList(); //Run different code depending on the command (duh) switch(command.Command) { case "mystatistics": //Always use the UID, NOT the username to identifiy users. Usernames can change. if (!userStatistics.ContainsKey(user.UID)) { //Here, we're setting the message that will be displayed for this chat message object. moduleOutput.message = "You have no statistics yet. You will after this message!"; } else { moduleOutput.message = GetUserStats(user); } //We add just the one output to our list of outputs (we only want to output one thing) outputs.Add(moduleOutput); break; case "statistics": if (command.Arguments.Count == 0) { moduleOutput.message = "---Global Chat Statistics---\n"; moduleOutput.message += "Total messages: " + allStats.Sum(x => x.TotalMessages) + "\n"; moduleOutput.message += "Average message size: " + (allStats.Count == 0 ? 0 : (int)(allStats.Sum(x => x.AverageMessageLength) / allStats.Count)) + " characters\n"; moduleOutput.message += "Total users seen: " + allStats.Count + "\n"; moduleOutput.message += "Total user chat time: " + StringExtensions.LargestTime(new TimeSpan(users.Sum(x => x.Value.TotalChatTime.Ticks))) + "\n"; moduleOutput.message += "Average session time: " + (users.Count == 0 ? "error" : StringExtensions.LargestTime(new TimeSpan(users.Sum(x => x.Value.AverageSessionTime.Ticks) / users.Count))) + "\n"; outputs.Add(moduleOutput); } else { //THIS IS IMPORTANT! Arguments containing a user will be given to you as a USERNAME! However, you want //to store their information based on their UID. This function "GetUserFromArgument()" will search through //the given dictionary to find you the user with the given username. It should always succeed, and puts the //result in the "out" parameter. You probably don't need to check the return of GetUserFromArgument like I //do, but just to be save, if it fails, you can just fail with a generic error. AddError adds a generic //module error to the given list of outputs, then you can return outputs and it'll contain that error. UserInfo findUser; if (!GetUserFromArgument(command.Arguments[0], users, out findUser)) { AddError(outputs); break; } moduleOutput.message = GetUserStats(findUser); outputs.Add(moduleOutput); } break; } return outputs; }
public override List<ChatEssentials.JSONObject> ProcessCommand(UserCommand command, ChatEssentials.UserInfo user, Dictionary<int, ChatEssentials.UserInfo> users) { #region oneTimeProcess if(!oneTimeRun) { oneTimeRun = true; //Cheating = ExplorerConstants.Simulation.FruitGrowthHours = GetOption<double>("fruitHours"); ExplorerConstants.Simulation.TreeGrowthHours = GetOption<double>("treeHours"); ExplorerConstants.Simulation.StoneGrowthHours = GetOption<double>("stoneHours"); ExplorerConstants.Simulation.SuperFruitGrowthHours = GetOption<double>("superFruitHours"); ExplorerConstants.Items.TorchSteps = GetOption<int>("torchSteps"); ExplorerConstants.Probability.CaveChance = GetOption<double>("caveChance"); ExplorerConstants.Player.HourlyStaminaRegain = GetOption<int>("hourlyStamina"); //ExplorerConstants.Player.FruitFullnessIncrease = GetOption<double>("fullnessIncrease"); ExplorerConstants.Player.FruitPerFullness = GetOption<double>("fruitPerFullness"); ExplorerConstants.Player.FullnessDecayMinutes = GetOption<double>("fullnessDecayMinutes"); ExplorerConstants.Items.ExtraFruitPerMagicStone = GetOption<double>("extraFruitPerMagicStone"); string temp = GetOption<string>("player"); if (temp.Length > 0) ExplorerConstants.Player.CurrentPlayerToken = temp[0]; if (GetOption<bool>("cheating")) Commands.Add(new ModuleCommand("excheat", new List<CommandArgument>(), "Get a crapload of resources")); } #endregion #region fromPostProcess if (worlds.Count == 0) { GenerateWorld(); } foreach (WorldInstance world in worlds) world.RefreshFullness((DateTime.Now - lastCommand).TotalMinutes / ExplorerConstants.Player.FullnessDecayMinutes); lastCommand = DateTime.Now; if ((DateTime.Now - lastRefresh).TotalHours >= 1.0 / ExplorerConstants.Player.HourlyStaminaRegain) { foreach (WorldInstance world in worlds) world.RefreshStamina((int)Math.Ceiling((DateTime.Now - lastRefresh).TotalHours * ExplorerConstants.Player.HourlyStaminaRegain)); lastRefresh = DateTime.Now; } foreach (WorldInstance world in worlds) world.SimulateTime(); #endregion Match match; Tuple<WorldInstance, string> results; TryRegister(user.UID); try { if(command.Command == "exmastertest") { if(!user.ChatControlExtended) return FastMessage("You don't have access to this command", true); int worldType; if (!int.TryParse(command.Arguments[0], out worldType)) worldType = 0; World world = new World(); world.Generate(worldType % ExplorerConstants.Generation.PresetBases.Count); world.GetFullMapImage(false).Save(StringExtensions.PathFixer(GetOption<string>("mapFolder")) + "test" + worldType + ".png"); return FastMessage("Test " + worldType + " map: " + GetOption<string>("mapLink") + "/test" + worldType + ".png"); } if(command.Command == "exmasterflagscatter") { if(!user.ChatControlExtended) return FastMessage("You don't have access to this command", true); int amount, world; if (!int.TryParse(command.Arguments[0], out amount) || amount > 10000) return FastMessage("You can't spawn that many flags!"); if (!int.TryParse(command.Arguments[1], out world) || !worlds.Any(x => x.Operating && x.WorldID == world)) return FastMessage("The world you gave was invalid!"); int actualCount = worlds.First(x => x.Operating && x.WorldID == world).WorldData.ScatterFlags(amount); ModuleJSONObject broadcast = new ModuleJSONObject("Hey, " + user.Username + " has just spawned " + actualCount + " flags in exgame world " + world + "!"); broadcast.broadcast = true; return new List<JSONObject>{ broadcast }; } #region mastergenerate //match = Regex.Match(chunk.Message, @"^\s*/exmastergenerate\s*([0-9]+)?\s*$"); if (command.Command == "exmastergenerate") { if(!user.ChatControlExtended) return FastMessage("You don't have access to this command", true); int givenCode; if (!int.TryParse(command.Arguments[0], out givenCode)) givenCode = 0; if (generateCode == -1) { generateCode = (int)(DateTime.Now.Ticks % 10000); return FastMessage("If you wish to generate a new world, type in the same command with this code: " + generateCode); } else { if (generateCode != givenCode) { generateCode = -1; return FastMessage("That was the wrong code. Code has been reset", true); } GenerateWorld(); generateCode = -1; return FastMessage("You've generated a new world!"); } } #endregion #region masterclose //match = Regex.Match(chunk.Message, @"^\s*/exmasterclose\s+([0-9]+)\s*([0-9]+)?\s*$"); if (command.Command == "exmasterclose")//match.Success) { // if (chunk.Username != Module.AllControlUsername) // return chunk.Username + ", you don't have access to this command"; if(!user.ChatControlExtended) return FastMessage("You don't have access to this command", true); int givenCode, givenWorld; if (!int.TryParse(command.Arguments[0], out givenWorld) || !worlds.Any(x => x.Operating && x.WorldID == givenWorld)) return FastMessage("The world you gave was invalid!", true); if (!int.TryParse(command.Arguments[1], out givenCode)) givenCode = 0; if (closeCode == -1) { closeCode = (int)(DateTime.Now.Ticks % 10000); closeWorld = givenWorld; return FastMessage("If you wish to close world " + closeWorld + " , type in the same command with this code: " + closeCode); } else { if (closeCode != givenCode || closeWorld != givenWorld) { closeCode = -1; closeWorld = -1; return FastMessage("That was the wrong code or world. Code has been reset", true); } string output = "You've closed world " + closeWorld; bool warning = false; WorldInstance world = worlds.FirstOrDefault(x => x.WorldID == closeWorld); if (world == null) { output = "Something went wrong. No worlds have been closed"; warning = true; } else { world.CloseWorld(); } closeWorld = -1; closeCode = -1; return FastMessage(output, warning); } } #endregion #region worldlist if (command.Command == "exworldlist")//Regex.IsMatch(chunk.Message, @"^\s*/exworldlist\s*$")) { string output = "List of all worlds:\n-------------------------------------"; foreach (WorldInstance world in worlds) { if (world.CanPlay) output += "\n-World " + world.WorldID + " * " + world.GetOwnedAcres().Count + " acre".Pluralify(world.GetOwnedAcres().Count); } return StyledMessage(output); } #endregion #region setworld //match = Regex.Match(chunk.Message, @"^\s*/exsetworld\s+([0-9]+)\s*$"); if (command.Command == "exsetworld")//match.Success) { int setWorld; if (!int.TryParse(command.Arguments[0], out setWorld)) return FastMessage("This is an invalid world selection", true); else if (!worlds.Any(x => x.WorldID == setWorld)) return FastMessage("There are no worlds with this ID", true); else if (allPlayers[user.UID].PlayingWorld == setWorld) return FastMessage("You're already playing on this world", true); WorldInstance world = worlds.FirstOrDefault(x => x.WorldID == setWorld); if (!world.CanPlay) return FastMessage("This world is unplayable", true); allPlayers[user.UID].PlayingWorld = setWorld; if (world.StartGame(user.UID, user.Username)) return FastMessage("You've entered World " + setWorld + " for the first time!"); else return FastMessage("You've switched over to World " + setWorld); } #endregion #region toggle match = Regex.Match(command.Command, @"extoggle([^\s]+)"); if (match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return FastMessage(results.Item1.ToggleOption(user.UID, match.Groups[1].Value)); } #endregion #region go //match = Regex.Match(chunk.Message, @"^\s*/exgo\s*(.*)\s*$"); if (command.Command == "exgo")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); int chatCoinGet = 0; string output = results.Item1.PerformActions(user.UID, command.Arguments[0]/*match.Groups[1].Value*/, out chatCoinGet); // // if (chatCoinGet > 0) // StandardCalls_RequestCoinUpdate(chatCoinGet, chunk.Username); return StyledMessage(output); } #endregion #region cheat if (command.Command == "excheat")//Regex.IsMatch(chunk.Message, @"^\s*/excheat\s*$") && Cheating) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); results.Item1.Cheat(user.UID); return FastMessage("You cheated some resources into existence!"); } #endregion #region itemlist if (command.Command == "exitemlist")//Regex.IsMatch(chunk.Message, @"^\s*/exitemlist\s*$")) { string output = ""; foreach (ItemBlueprint item in ExplorerConstants.Items.AllBlueprints .Where(x => x.Key != ExplorerConstants.Items.IDS.ChatCoins).Select(x => x.Value) .Where(x => x.CanPickup && x.CanObtain || ExplorerConstants.Items.CraftingRecipes.ContainsKey(x.ID))) { output += item.ShorthandName + " (" + item.DisplayCharacter + ") - " + item.DisplayName + "\n"; } return StyledMessage(output); } #endregion #region equip //match = Regex.Match(chunk.Message, @"^\s*/exequip\s+([a-zA-Z]+)\s*$"); if (command.Command == "exequip")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return FastMessage(results.Item1.EquipItem(user.UID, command.Arguments[0].Trim()));//match.Groups[1].Value.Trim()); } #endregion #region craft //match = Regex.Match(chunk.Message, @"^\s*/excraft\s+([^0-9]+)\s*([0-9]*)\s*$"); if (command.Command == "excraft")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); int amount; if (!int.TryParse(/*match.Groups[2].Value*/command.Arguments[1], out amount)) amount = 1; return FastMessage(results.Item1.CraftItem(user.UID, command.Arguments[0].Trim()/*match.Groups[1].Value.Trim()*/, amount)); } #endregion #region craftlist if (command.Command == "excraftlist")//Regex.IsMatch(chunk.Message, @"^\s*/excraftlist\s*$")) { string output = ""; foreach (var craftRecipe in ExplorerConstants.Items.CraftingRecipes.OrderBy(x => x.Value.Values.Sum())) { output += ExplorerConstants.Items.AllBlueprints[craftRecipe.Key].ShorthandName + " - "; foreach (var craftIngredient in craftRecipe.Value) { output += ExplorerConstants.Items.AllBlueprints[craftIngredient.Key].ShorthandName + "*" + craftIngredient.Value + " "; } output += "\n"; } return StyledMessage(output); } #endregion #region map //match = Regex.Match(chunk.Message, @"^\s*/exmap\s+([0-9]+)\s*$"); if (command.Command == "exmap")//match.Success) { //return FastMessage("Not supported right now!", true); int worldID; if (!int.TryParse(command.Arguments[0], out worldID)) return FastMessage("That's not a valid number", true); if (!worlds.Any(x => x.WorldID == worldID)) return FastMessage("There's no world with this ID", true); try { SaveWorldImage(worlds.FirstOrDefault(x => x.WorldID == worldID)); } catch (Exception e) { return FastMessage("An error occurred while generating the map image! Please report this error to an admin." + "\nError: " + e, true); } return FastMessage("World " + worldID + " map: " + GetOption<string>("mapLink") + "/world" + worldID + ".png"); } #endregion #region top if (command.Command == "extop")//Regex.IsMatch(chunk.Message, @"^\s*/extop\s*$")) { List<string> scores = SortedModuleItems(users); //List<Tuple<string, int>> scores = allPlayers.Select(x => Tuple.Create(x.Key, worlds.Sum(y => y.GetScore(x.Key)))).ToList(); string output = "The top explorers are:"; for (int i = 0; i < 5; i++) if (i < scores.Count()) output += "\n" + (i + 1) + ": " + scores[i]; return FastMessage(output); } #endregion #region close if (command.Command == "exclose")//Regex.IsMatch(chunk.Message, @"^\s*/exclose\s*$")) { List<string> scores = SortedModuleItems(users); //List<Tuple<string, int>> scores = allPlayers.Select(x => Tuple.Create(x.Key, worlds.Sum(y => y.GetScore(x.Key)))).ToList(); int index = scores.FindIndex(x => x.Contains(user.Username + " ")); string output = "Your exploration competitors are:"; for (int i = index - 2; i <= index + 2; i++) if (i < scores.Count() && i >= 0) output += "\n" + (i + 1) + ": " + scores[i]; return FastMessage(output); } #endregion #region respawn if (command.Command == "exrespawn")//Regex.IsMatch(chunk.Message, @"^\s*/exrespawn\s*$")) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return StyledMessage(results.Item1.Respawn(user.UID)); } #endregion #region myacres if (command.Command == "exmyacres")//Regex.IsMatch(chunk.Message, @"^\s*/exmyacres\s*$")) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return FastMessage(results.Item1.PlayerAcres(user.UID)); } #endregion #region items if (command.Command == "exitems")//Regex.IsMatch(chunk.Message, @"^\s*/exitems\s*$")) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return StyledMessage(results.Item1.PlayerItems(user.UID)); } #endregion #region storage if (command.Command == "exstorage")//Regex.IsMatch(chunk.Message, @"^\s*/exitems\s*$")) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); return StyledMessage(results.Item1.PlayerStorage(user.UID)); } #endregion #region store //match = Regex.Match(chunk.Message, @"^\s*/excraft\s+([^0-9]+)\s*([0-9]*)\s*$"); if (command.Command == "exstore")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); int amount; if (!int.TryParse(/*match.Groups[2].Value*/command.Arguments[1], out amount)) amount = int.MaxValue; return FastMessage(results.Item1.StoreItems(user.UID, command.Arguments[0].Trim()/*match.Groups[1].Value.Trim()*/, amount)); } #endregion #region store //match = Regex.Match(chunk.Message, @"^\s*/excraft\s+([^0-9]+)\s*([0-9]*)\s*$"); if (command.Command == "extake")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); int amount; if (!int.TryParse(/*match.Groups[2].Value*/command.Arguments[1], out amount)) amount = int.MaxValue; return FastMessage(results.Item1.TakeItems(user.UID, command.Arguments[0].Trim()/*match.Groups[1].Value.Trim()*/, amount)); } #endregion #region teleport //match = Regex.Match(chunk.Message, @"^\s*/exteleport\s+([0-9]+)\s*-\s*([0-9]+)\s*$"); if (command.Command == "exteleport")//match.Success) { if (!WorldCommandCheck(user.UID, out results)) return FastMessage(results.Item2, true); int x, y; if (!int.TryParse(command.Arguments[0], out x) || !int.TryParse(command.Arguments[1], out y)) return FastMessage("Your acre was formatted incorrectly!", true); return StyledMessage(results.Item1.TeleportToTower(user.UID, Tuple.Create(x, y))); } #endregion } catch (Exception e) { return FastMessage("An exception occurred: " + e.Message + ". Please report to an admin\n" + "Stack trace: \n" + e.StackTrace, true); } return new List<JSONObject>(); }
public List<JSONObject> StyledMessage(string message)//, bool warning = false) { ModuleJSONObject output = new ModuleJSONObject(); output.message = "<span style=\"display: block; font-family:'Courier New', Courier, monospace; line-height: 100%;\">" + message + "</span>"; output.safe = false; return new List<JSONObject> { output }; }
public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { List<JSONObject> outputs = new List<JSONObject>(); ModuleJSONObject moduleOutput = new ModuleJSONObject(); VoteBallot ballot; string error = ""; string output = ""; long pollNumber = 0; if (!userBallots.ContainsKey(user.UID)) userBallots.Add(user.UID, new List<VoteBallot>()); try { switch(command.Command) { case "pollcreate": int maxPolls = MaxUserPolls * (user.CanStaffChat ? 5 : 1); if (userBallots[user.UID].Count >= maxPolls) return FastMessage("You've reached the maximum amount of allowed polls (" + maxPolls + ") and cannot post a new one", true); else if (command.ArgumentParts[1].Count > MaxPollChoices) return FastMessage("There are too many choices in your poll! The max is " + MaxPollChoices, true); VoteBallot newBallot = new VoteBallot(command.Arguments[0], new HashSet<string>(command.ArgumentParts[1])); if (newBallot.GetChoices().Count < 2) return FastMessage("Your poll must have at least 2 options", true); userBallots[user.UID].Add(newBallot); moduleOutput.broadcast = true; moduleOutput.message = "A new poll has been created by " + user.Username + ":\n\n" + userBallots[user.UID].Last(); outputs.Add(moduleOutput); break; case "vote": if(!long.TryParse(command.Arguments[1], out pollNumber)) return FastMessage("Your poll number is out of bounds!", true); if(!GetBallot(pollNumber, false, out ballot)) { return FastMessage("There is no open poll with ID " + pollNumber); } else { if(!ballot.AddVote(user.UID, command.Arguments[0], out error)) return FastMessage(error); else return FastMessage("You voted on this poll: \n\n" + ballot.GetResultString(user.UID)); } case "polls": output = "The top polls right now: \n"; output += PrintList(userBallots.SelectMany(x => x.Value).OrderByDescending(x => x.TotalVotes).Take(10)); return FastMessage(output); case "poll": if(!long.TryParse(command.Arguments[0], out pollNumber)) return FastMessage("Your poll number is out of bounds!", true); if(!GetBallot(pollNumber, true, out ballot)) { return FastMessage("There is no open poll with ID " + pollNumber); } else { output = ""; bool closed = archivedBallots.SelectMany(x => x.Value).Contains(ballot); if(ballot.DidVote(user.UID) || closed) output = ballot.GetResultString(user.UID); else output = ballot.ToString(); int ballotCreator = userBallots.Union(archivedBallots).First(x => x.Value.Contains(ballot)).Key; output += "\nPoll by: " + users[ballotCreator].Username + (closed ? " (closed)" : ""); return FastMessage(output); } case "pollclose": if(!long.TryParse(command.Arguments[0], out pollNumber)) return FastMessage("Your poll number is out of bounds!", true); if(!userBallots[user.UID].Any(x => x.ID == pollNumber)) return FastMessage("You don't have any open polls with this ID!"); if(!GetBallot(pollNumber, false, out ballot)) { return FastMessage("There is no open poll with ID " + pollNumber); } else { if(!archivedBallots.ContainsKey(user.UID)) archivedBallots.Add(user.UID, new List<VoteBallot>()); archivedBallots[user.UID].Add(ballot); userBallots[user.UID].Remove(ballot); moduleOutput.broadcast = true; moduleOutput.message = "The poll " + ballot.Title + " has just been closed by " + user.Username + ". The results:\n\n" + ballot.GetResultString(); outputs.Add(moduleOutput); } break; case "pollsearch": List<Tuple<double, VoteBallot>> sortedBallots = new List<Tuple<double, VoteBallot>>(); foreach(VoteBallot searchBallot in userBallots.SelectMany(x => x.Value).Union(archivedBallots.SelectMany(x => x.Value))) sortedBallots.Add(Tuple.Create(StringExtensions.StringDifference(command.Arguments[0].ToLower(), searchBallot.Title.ToLower()), searchBallot)); output = "These ballots have a similar title: \n"; output += PrintList(sortedBallots.OrderBy(x => x.Item1).Select(x => x.Item2).Take(SearchResults)); return FastMessage(output); case "pollsopen": output = "Your open polls right now are: \n" + PrintList(userBallots[user.UID]); return FastMessage(output); } } catch(Exception e) { return new List<JSONObject>() { new ModuleJSONObject() { message = "Something terrible happened in the Vote module: " + e, broadcast = true } }; } return outputs; }
public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { List<JSONObject> outputs = new List<JSONObject>(); ModuleJSONObject moduleOutput = new ModuleJSONObject(); string message = ""; UserInfo parsedInfo; try { switch(command.Command) { case "spamscore": moduleOutput.message = "Your spam score is: " + user.SpamScore + ", offense score: " + user.GlobalSpamScore; outputs.Add(moduleOutput); break; case "resetserver": int timeout = 5; //Get the real timeout if one was given if (command.Arguments.Count > 0 && !string.IsNullOrWhiteSpace(command.Arguments[0])) timeout = int.Parse(command.Arguments[0]); TimeSpan realTimeout = TimeSpan.FromSeconds(timeout); //Make sure the user can even run such a high command if(!user.ChatControl) return FastMessage("You don't have access to this command!", true); //Request the reset we wanted ChatRunner.PerformRequest(new SystemRequest(SystemRequests.Reset, realTimeout)); moduleOutput.message = user.Username + " is resetting the server in " + StringExtensions.LargestTime(realTimeout); moduleOutput.broadcast = true; outputs.Add(moduleOutput); break; case "simulatelock": //Make sure the user can even run such a high command if(!user.ChatControlExtended) return FastMessage("You don't have access to this command!", true); //Request the lock we wanted ChatRunner.PerformRequest(new SystemRequest(SystemRequests.LockDeath, TimeSpan.FromSeconds(5))); moduleOutput.message = user.Username + " is simulating a server crash. The server WILL be unresponsive if successful"; moduleOutput.broadcast = true; outputs.Add(moduleOutput); break; case "savemodules": //Make sure the user can even run such a high command if(!user.ChatControlExtended) return FastMessage("You don't have access to this command!", true); ChatRunner.PerformRequest(new SystemRequest(SystemRequests.SaveModules)); moduleOutput.message = user.Username + " is saving all module data. This may cause a small hiccup"; moduleOutput.broadcast = true; outputs.Add(moduleOutput); break; case "checkserver": //Make sure the user can even run such a high command if(!user.ChatControl) return FastMessage("You don't have access to this command!", true); message = "Information about the chat server:\n\n"; Dictionary<string, List<UserMessageJSONObject>> history = ChatRunner.Server.GetHistory(); List<UserMessageJSONObject> messages = ChatRunner.Server.GetMessages(); List<LogMessage> logMessages = ChatRunner.Server.Settings.LogProvider.GetMessages(); List<LogMessage> logFileBuffer = ChatRunner.Server.Settings.LogProvider.GetFileBuffer(); List<Module> modules = ChatRunner.Server.GetModuleListCopy(); message += "Rooms: " + history.Keys.Count + "\n"; message += "History messages: " + history.Sum(x => x.Value.Count) + "\n"; message += "Registered users: " + users.Count + "\n"; message += "Total user sessions: " + users.Sum(x => (long)x.Value.SessionCount) + "\n"; message += "Stored messages: " + messages.Count + "\n"; message += "Stored log: " + logMessages.Count + "\n"; message += "Log file buffer: " + logFileBuffer.Count + "\n"; message += "Modules loaded: " + string.Join(", ", modules.Select(x => x.GetType().Name)) + " (" + modules.Count + ")\n"; message += "Subscribed handlers for extra output: " + this.ExtraCommandHandlerCount + "\n"; message += "Registered connections: " + ChatRunner.Server.ConnectedUsers().Count + "\n"; using(Process process = Process.GetCurrentProcess()) { message += "Virtual Memory: " + (process.PrivateMemorySize64 / 1048576) + "MiB\n"; message += "Heap Allocated: " + (GC.GetTotalMemory(true) / 1048576) + "MiB\n"; message += "Threads: " + process.Threads.Count; } moduleOutput.message = message; outputs.Add(moduleOutput); break; case "debuginfo": //if we can't parse the user, use yourself. Otherwise if it parsed but they don't have //access to this command, stop and let them know. if(string.IsNullOrWhiteSpace(command.Arguments[0]) || !GetUserFromArgument(command.Arguments[0], users, out parsedInfo)) parsedInfo = user; else if(!user.ChatControl && parsedInfo.UID != user.UID) return FastMessage("You don't have access to this command!", true); message = parsedInfo.Username + "'s debug information: \n\n"; message += "Session ID: " + parsedInfo.LastSessionID + "\n"; message += "Open sessions: " + parsedInfo.OpenSessionCount + "\n"; message += "Bad sessions: " + parsedInfo.BadSessionCount + "\n"; message += "Current session time: " + StringExtensions.LargestTime(parsedInfo.CurrentSessionTime) + "\n"; message += "UID: " + parsedInfo.UID + "\n"; message += "Active: " + parsedInfo.Active + "\n"; message += "Last ping: " + StringExtensions.LargestTime(DateTime.Now - parsedInfo.LastPing) + "\n"; message += "Last post: " + StringExtensions.LargestTime(DateTime.Now - parsedInfo.LastPost) + "\n"; message += "Last entry: " + StringExtensions.LargestTime(DateTime.Now - parsedInfo.LastJoin) + "\n"; message += "Staff chat: " + parsedInfo.CanStaffChat + "\n"; message += "Global chat: " + parsedInfo.CanGlobalChat + "\n"; message += "Chat control: " + parsedInfo.ChatControl + "\n"; message += "Chat control extended: " + parsedInfo.ChatControlExtended + "\n"; message += "Avatar: " + user.Avatar + "\n"; moduleOutput.message = message; outputs.Add(moduleOutput); break; } } catch (Exception e) { return FastMessage("An error has occurred in the debug module: " + e.Message, true); } return outputs; }
public void SendMessage(ModuleJSONObject message) { //List<Chat> recipients = new List<Chat>(); // List<Chat> CurrentChatters = ConnectedUsers().Select(x => (Chat)x).ToList(); // // lock (managerLock) // { // Log("Enter sendmessage lock", MyExtensions.Logging.LogLevel.Locks); // foreach (int user in message.recipients.Distinct()) // { // if (activeChatters.Any(x => x.UID == user)) // recipients.Add(activeChatters.First(x => x.UID == user)); // else // Logger.LogGeneral("Recipient " + user + " in module message was not found", MyExtensions.Logging.LogLevel.Warning); // } // Log("Leave sendmessage lock", MyExtensions.Logging.LogLevel.Locks); // } List<Chat> recipients = ConnectedUsers().Select(x => (Chat)x).Where(x => message.recipients.Contains(x.UID)).ToList(); foreach(Chat recipient in recipients) recipient.MySend(message.ToString()); }
public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { List<JSONObject> outputs = new List<JSONObject>(); ModuleJSONObject output = new ModuleJSONObject(); switch (command.Command) { case "about": output = new ModuleJSONObject(); BandwidthContainer bandwidth = ChatRunner.Bandwidth; //Chat.GetBandwidth(); DateTime built = ChatRunner.MyBuildDate(); DateTime crashed = ChatRunner.LastCrash(); string crashedString = "never"; if (crashed.Ticks > 0) crashedString = StringExtensions.LargestTime(DateTime.Now - crashed) + " ago"; output.message = "---Build info---\n" + "Version: " + ChatRunner.AssemblyVersion() + "\n" + "Runtime: " + StringExtensions.LargestTime(DateTime.Now - ChatRunner.Startup) + "\n" + "Built " + StringExtensions.LargestTime(DateTime.Now - built) + " ago (" + built.ToString("R") + ")\n" + "---Data usage---\n" + "Outgoing: " + bandwidth.GetTotalBandwidthOutgoing() + " (1h: " + bandwidth.GetHourBandwidthOutgoing() + ")\n" + "Incoming: " + bandwidth.GetTotalBandwidthIncoming() + " (1h: " + bandwidth.GetHourBandwidthIncoming() + ")\n" + "---Websocket---\n" + "Library Version: " + WebSocketServer.Version + "\n" + "Last full crash: " + crashedString; outputs.Add(output); break; case "policy": output = new ModuleJSONObject(ChatServer.Policy); outputs.Add(output); break; case "help": output = new ModuleJSONObject(); if (command.Arguments.Count == 0) { output.message = "Which module would you like help with?\n"; foreach (Module module in ChatRunner.Server.GetModuleListCopy(user.UID)) output.message += "\n" + module.Nickname; output.message += "\n\nRerun help command with a module name to see commands for that module"; outputs.Add(output); } else { output.message = GetModuleHelp(command.Arguments[0], user); outputs.Add(output); } break; case "helpregex": output.message = GetModuleHelp(command.Arguments[0], user, true); outputs.Add(output); break; case "uactest": output = new ModuleJSONObject(); output.message = "User " + command.OriginalArguments[0] + " corrects to " + command.Arguments[0]; outputs.Add(output); break; } return outputs; }
// protected override void OnError(ErrorEventArgs e) // { // if(e.Message != null) // Logger.Error("UID: " + uid + " - " + e.Message, "WebSocket"); // if(e.Exception != null) // Logger.Error(e.Exception.ToString(), "WebSocket"); // // //OK let's see what happens here // //OnClose(null); // //base.OnError(e); // } //I guess this is WHENEVER it receives a message? public override void ReceivedMessage(string rawMessage) { //Log("Got message: " + rawMessage, MyExtensions.Logging.LogLevel.Debug); ResponseJSONObject response = new ResponseJSONObject(); response.result = false; dynamic json = new Object(); string type = ""; //You HAVE to do this, even though it seems pointless. Users need to show up as banned immediately. ThisUser.PullInfoFromQueryPage(); //Before anything else, log the amount of incoming data if (!string.IsNullOrEmpty(rawMessage)) { manager.Bandwidth.AddIncoming(rawMessage.Length + HeaderSize); } //First, just try to parse the JSON they gave us. If it's absolute //garbage (or just not JSON), let them know and quit immediately. try { json = JsonConvert.DeserializeObject(rawMessage); type = json.type; response.from = type; } catch { response.errors.Add("Could not parse JSON"); } //If we got a bind message, let's try to authorize this channel. if (type == "bind") { if (uid > 0) { response.errors.Add("Received another bind message, but you've already been authenticated."); } else { try { //First, gather information from the JSON. This is so that if //the json is invalid, it will fail as soon as possible string key = (string)json.key; int newUser = (int)json.uid; //Oops, username was invalid if (newUser <= 0) { Log("Tried to bind a bad UID: " + newUser); response.errors.Add("UID was invalid"); } else { //List<Chat> removals; string error; if (!manager.CheckAuthentication(newUser, key, out error)) //newUser, key, out removals, out error)) { response.errors.Add(error); } else { //Before we do anything, remove other chatting sessions foreach (Chat removeChat in GetAllUsers().Select(x => (Chat)x).Where(x => x.UID == newUser && x != this)) removeChat.CloseSelf(); //Sessions.CloseSession(removeChat.ID); uid = newUser; //BEFORE adding, broadcast the "whatever has entered the chat" message if (ThisUser.ShowMessages) { manager.Broadcast(QuickParams(ChatTags.Join), new SystemMessageJSONObject(), new List<Chat> { this }); } MySend(NewSystemMessageFromTag(QuickParams(ChatTags.Welcome)).ToString()); ChatTags enterSpamWarning = ThisUser.JoinSpam(); if (enterSpamWarning != ChatTags.None) MySend(NewWarningFromTag(QuickParams(enterSpamWarning)).ToString()); //BEFORE sending out the user list, we need to perform onPing so that it looks like this user is active sessionID = ThisUser.PerformOnChatEnter(); // if (!ThisUser.PerformOnChatEnter()) // Log("Invalid session entry. Sessions may be broken", LogLevel.Warning); manager.BroadcastUserList(); Log("Authentication complete: UID " + uid + " maps to username " + ThisUser.Username + (ThisUser.CanStaffChat ? "(staff)" : "")); response.result = true; List<JSONObject> outputs = new List<JSONObject>(); Dictionary<int, UserInfo> currentUsers = manager.UsersForModules(); //Also do some other crap foreach (Module module in manager.GetModuleListCopy()) { if (Monitor.TryEnter(module.Lock, manager.ChatSettings.MaxModuleWait)) { try { outputs.AddRange(module.OnUserJoin(currentUsers[ThisUser.UID], currentUsers)); } finally { Monitor.Exit(module.Lock); } } else { Log("Skipped " + module.ModuleName + " join processing", MyExtensions.Logging.LogLevel.Warning); } } OutputMessages(outputs, ThisUser.UID); //Finally, output the "Yo accept dis" thing if they haven't already. if(!ThisUser.AcceptedPolicy) { MessageListJSONObject emptyMessages = new MessageListJSONObject(); UserListJSONObject emptyUsers = new UserListJSONObject(); ModuleJSONObject policy = new ModuleJSONObject(ChatServer.Policy); ModuleJSONObject accept = new ModuleJSONObject("\nYou must accept this chat policy before " + "using the chat. Type /accept if you accept the chat policy\n"); MySend(emptyMessages.ToString(), true); MySend(emptyUsers.ToString(), true); MySend(policy.ToString(), true); MySend(accept.ToString(), true); } else if(ThisUser.ShouldPolicyRemind) { ModuleJSONObject policy = new ModuleJSONObject(ChatServer.Policy); MySend(policy.ToString()); ThisUser.PerformOnReminder(); } //Now set up the IRC relay. Oh boy, let's hope this works! /*relay = new SimpleIRCRelay(manager.IrcServer, manager.IrcChannel, ThisUser.Username, Logger); relay.ConnectAsync();*/ //relay.IRCRelayMessageEvent += OnIrcRelayMessage; } } } catch { response.errors.Add("BIND message was missing fields"); } } } else if (type == "ping") { lastPing = DateTime.Now; bool active = true; try { active = (bool)json.active; //relay.Ping(); } catch (Exception messageError) { response.errors.Add("Internal server error: " + messageError/*.Message*/); } ThisUser.PerformOnPing(active); UpdateActiveUserList(null, null); } else if (type == "message") { try { //First, gather information from the JSON. This is so that if //the json is invalid, it will fail as soon as possible string key = json.key; string message = System.Security.SecurityElement.Escape((string)json.text); string tag = json.tag; //These first things don't increase spam score in any way if (string.IsNullOrWhiteSpace(message)) { response.errors.Add("No empty messages please"); } else if (!manager.CheckKey(uid, key)) { Log("Got invalid key " + key + " from " + UserLogString); response.errors.Add("Your key is invalid"); } else if (!ThisUser.AcceptedPolicy) { if(message != "/accept") { response.errors.Add("The only command available right now is /accept"); } else { ModuleJSONObject acceptSuccess = new ModuleJSONObject("You have accepted the SmileBASIC Source " + "chat policy. Please use the appropriate chat tab for discussion about SmileBASIC or off-topic " + "subjects!"); MySend(acceptSuccess.ToString(), true); Thread.Sleep(2000); ThisUser.AcceptPolicy(); ThisUser.PerformOnReminder(); response.result = true; MySend(manager.ChatUserList(UID)); MySend(manager.ChatMessageList(UID)); } } else if (ThisUser.Blocked) { response.errors.Add(NewWarningFromTag(QuickParams(ChatTags.Blocked)).message); } else if (ThisUser.Banned) { response.errors.Add("You are banned from chat for " + StringExtensions.LargestTime(ThisUser.BannedUntil - DateTime.Now)); } else if (tag == "admin" && !ThisUser.CanStaffChat || tag == manager.ChatSettings.GlobalTag && !ThisUser.CanGlobalChat) { response.errors.Add("You can't post messages here. I'm sorry."); } else if (!manager.ValidTagForUser(UID, tag)) { response.errors.Add("Your post has an unrecognized tag. Cannot display"); } else { Dictionary<int, UserInfo> currentUsers = manager.UsersForModules(); List<JSONObject> outputs = new List<JSONObject>(); UserMessageJSONObject userMessage = new UserMessageJSONObject(ThisUser, message, tag); UserCommand userCommand; Module commandModule; string commandError = ""; //Step 1: parse a possible command. If no command is parsed, no module will be written. if (TryCommandParse(userMessage, out commandModule, out userCommand, out commandError)) { Log("Trying to use module " + commandModule.ModuleName + " to process command " + userCommand.message + " from " + ThisUser.Username, MyExtensions.Logging.LogLevel.SuperDebug); //We found a command. Send it off to the proper module and get the output if (Monitor.TryEnter(commandModule.Lock, manager.ChatSettings.MaxModuleWait)) { try { outputs.AddRange(commandModule.ProcessCommand(userCommand, currentUsers[ThisUser.UID], currentUsers)); } finally { Monitor.Exit(commandModule.Lock); } } else { response.errors.Add("The chat server is busy and can't process your command right now"); userMessage.SetHidden(); userMessage.SetUnspammable(); } //do not update spam score if command module doesn't want it if (!userCommand.MatchedCommand.ShouldUpdateSpamScore) userMessage.SetUnspammable(); //For now, simply capture all commands no matter what. userMessage.SetHidden(); //userMessage.SetCommand(); Log("Module " + commandModule.ModuleName + " processed command from " + UserLogString, MyExtensions.Logging.LogLevel.Debug); } else { //If an error was given, add it to our response if (!string.IsNullOrWhiteSpace(commandError)) { response.errors.Add("Command error: " + commandError); userMessage.SetHidden(); userMessage.SetUnspammable(); } } ChatTags warning = manager.AddMessage(userMessage); //Send off on relay /*if(userMessage.Display && userMessage.tag == manager.IrcTag) { if(relay.SendMessage(userMessage.message)) Logger.LogGeneral("Sent message on IRC relay!", MyExtensions.Logging.LogLevel.SuperDebug); else Logger.LogGeneral("Couldn't send on IRC relay!", MyExtensions.Logging.LogLevel.SuperDebug); }*/ if (warning != ChatTags.None) outputs.Add(NewWarningFromTag(QuickParams(warning))); response.result = response.errors.Count == 0; //Now send out userlist if active status changed UpdateActiveUserList(null, null); //Since we added a new message, we need to broadcast. if (response.result && userMessage.Display) manager.BroadcastMessageList(); //CRASH ALMOST CERTAINLY HAPPENS HERE!!!!!!!###$$$$$!!!!!!!!!!*$*$*$* //Step 2: run regular message through all modules' regular message processor (probably no output?) if(manager.ChatSettings.AcceptedTags.Contains(userMessage.tag)) { foreach (Module module in manager.GetModuleListCopy()) { if (Monitor.TryEnter(module.Lock, manager.ChatSettings.MaxModuleWait)) { try { module.ProcessMessage(userMessage, currentUsers[ThisUser.UID], currentUsers); } finally { Monitor.Exit(module.Lock); } } else { Log("Skipped " + module.ModuleName + " message processing", MyExtensions.Logging.LogLevel.Warning); } } } //Step 3: run all modules' post processor (no message required) //Is this even necessary? It was necessary before because the bot ran on a timer. Without a timer, //each module can just specify that it wants to do things at random points with its own timer. //Step 4: iterate over returned messages and send them out appropriately OutputMessages(outputs, ThisUser.UID, tag); //end of regular message processing } } catch (Exception messageError) { response.errors.Add("Internal server error: " + messageError/*.Message*/); //response.errors.Add("Message was missing fields"); } } // else if (type == "createroom") // { // try // { // List<int> users = json.users.ToObject<List<int>>(); // string error; // // if(!manager.CreatePMRoom(new HashSet<int>(users), ThisUser.UID, out error)) // { // response.errors.Add(error); // } // else // { // MySend((new SystemMessageJSONObject("You created a chat room for " + string.Join(", ", users.Select(x => manager.GetUser(x).Username)))).ToString()); // manager.BroadcastUserList(); // } // } // catch // { // response.errors.Add("Could not parse PM creation room message"); // } // } else if (type == "request") { try { string wanted = json.request; if(wanted == "userList") { MySend(manager.ChatUserList(UID)); response.result = true; } else if (wanted == "messageList") { MySend(manager.ChatMessageList(UID)); response.result = true; } else { response.errors.Add("Invalid request field"); } } catch { response.errors.Add("Request was missing fields"); } } //Send the "OK" message back. MySend(response.ToString(), true); }
public void SendMessage(ModuleJSONObject message) { List<Chat> recipients = ConnectedUsers().Select(x => (Chat)x).Where(x => message.recipients.Contains(x.UID)).ToList(); foreach(Chat recipient in recipients) recipient.MySend(message.ToString()); }
public override List<JSONObject> ProcessCommand(UserCommand command, UserInfo user, Dictionary<int, UserInfo> users) { try { //Match match; string cmd = command.Command; int myUID = user.UID; UserInfo player; ModuleJSONObject mainOutput = new ModuleJSONObject(); List<JSONObject> outputs = new List<JSONObject>(); TryRegister(user.UID); //Top collectors #region topcollectors if (cmd == "cgametop") { var topCollectors = collectors.ToList().OrderByDescending(x => x.Value.Score()).ToList(); string output = "The top collectors are:"; for (int i = 0; i < 5; i++) if (i < topCollectors.Count()) output += "\n" + (i + 1) + ": " + QuickInfo(users[topCollectors[i].Key]); return QuickQuit(output); } #endregion //Close collectors #region closecollectors else if (cmd == "cgameclose") { var topCollectors = collectors.ToList().OrderByDescending(x => x.Value.Score()).ToList(); int index = topCollectors.FindIndex(x => x.Key == myUID); string output = "Your competitors are:"; for (int i = index - 2; i <= index + 2; i++) if (i < topCollectors.Count() && i >= 0) output += "\n" + (i + 1) + ": " + QuickInfo(users[topCollectors[i].Key]); return QuickQuit(output); } #endregion //Collect your daily coins #region coinrestock else if (cmd == "cgamerestock") { if (collectors[myUID].RestockCoins(DateTime.Now)) { return QuickQuit("You received " + collectors[myUID].RestockCoinsAmount() + " coins for the " + CollectionManager.RestockHours + "-hour reset. You now have " + collectors[myUID].Coins + " coins"); } else { return QuickQuit("You've already received your coins for this " + CollectionManager.RestockHours + " hour period.\n" + "Please wait another " + StringExtensions.LargestTime(collectors[myUID].RestockWait)); } } #endregion //Try to rank up #region rankup else if (cmd == "cgamerankup") { if (collectors[myUID].RankUp()) { string output = "You've ranked up! Your inventory and journal have been cleared, and you are now rank " + collectors[myUID].Stars; // if (!StandardCalls_RequestCoinUpdate(RankupCoins, username)) // output += Module.SendMessageBreak + "Unfortunately, the ChatCoin module seems to be malfunctioning, so you will not receive coins"; mainOutput.broadcast = true; mainOutput.message = "Hey, " + user.Username + " has become rank " + collectors[myUID].Stars + "(" + collectors[myUID].StarString() + ") in the cgame!"; outputs = QuickQuit(output); outputs.Add(mainOutput); return outputs; //return QuickQuit(output); } else { return QuickQuit("You can't rank up just yet. Complete your journal first!"); } } #endregion //View your collection #region mycollection else if (cmd == "cgamestock") { return QuickQuit("-=Your collection=-\n" + collectors[myUID].Statistics(false, JournalStyle), false, false); } else if (cmd == "cgamestockm") { return QuickQuit("-=Your collection=-\n" + collectors[myUID].Statistics(true, JournalStyle), false, false); } #endregion //View your top items #region mytopitems else if (cmd == "cgametopitems") { var topItems = collectors[myUID].Inventory.AllItemCounts().ToList().OrderByDescending(x => x.Value).ToList(); string output = "The top items in your inventory are: "; for (int i = 0; i < 5; i++) if (i < topItems.Count) output += "\n" + CollectionSymbols.GetPointAndSymbol(topItems[i].Key) + " - " + topItems[i].Value; return QuickQuit(output); } #endregion //Get multiple items #region drawitems //match = Regex.Match(message, @"^\s*/cgamedraw\s*([0-9]+)?\s*([xX][0-9]+)?\s*$"); else if (cmd == "cgamedraw") { int multiplier = 1; int amount; //Oops, bad amount number if (!int.TryParse(command.Arguments[0], out amount)) return QuickQuit("The amount of items to draw is invalid", true); else if (amount <= 0 || amount > MaxWithdraw) return QuickQuit("You can't withdraw that many items!", true); //We had a multiplier! if(command.Arguments.Count == 2) { if (!int.TryParse(command.Arguments[1].ToLower().Replace("x", ""), out multiplier)) return QuickQuit("The multiplier is invalid", true); else if (multiplier > CollectionManager.MaxMultiplier || multiplier < CollectionManager.MinMultiplier) return QuickQuit("Your multiplier is out of range. Use values from " + CollectionManager.MinMultiplier + "-" + CollectionManager.MaxMultiplier, true); } int cost = CollectionManager.LotteryCost * multiplier * amount; //Oops, you don't have enough coins if (collectors[myUID].Coins < cost) return QuickQuit("You don't have enough coins. Drawing " + amount + " item".Pluralify(amount) + " with a multiplier of X" + multiplier + " costs " + cost + " coins."); //Generate a list of items (based on the given amount) List<SpecialPoint> items = new List<SpecialPoint>(); List<SpecialPoint> newItems = new List<SpecialPoint>(); for (int i = 0; i < amount; i++) { items.Add(generator.DrawItemForPlayer(collectors[myUID], multiplier)); if (!collectors[myUID].Journal.HasItem(items[i])) newItems.Add(items[i]); //Make the player "buy" the item collectors[myUID].BuyItem(items[i], cost / amount); } string output = "You spent " + cost + " coins on item".Pluralify(items.Count) + ": "; int newItemCount = 0; //Go through each item and buy it/produce output foreach (SpecialPoint drawnItem in items) { //Determine if the item is new. Update values if so bool newItem = false; if (newItems.Contains(drawnItem)) { newItem = true; newItems.RemoveAll(x => x == drawnItem); newItemCount++; } //Update output output += CollectionSymbols.GetPointAndSymbol(drawnItem) + (newItem ? "**" : "") + ", "; } output += ListTerminator + " (" + newItemCount + " new)"; return QuickQuit(output.Replace(", " + ListTerminator, "")); } #endregion //See the chance of getting a new item #region drawchance //match = Regex.Match(message, @"^\s*/cgamechance\s*([xX][0-9]+)?\s*$"); else if (cmd == "cgamechance") { int multiplier = 1; //Oops, bad multiplier if (!int.TryParse(command.Arguments[0].ToLower().Replace("x", ""), out multiplier)) return QuickQuit("The multiplier is invalid!", true); else if (multiplier > CollectionManager.MaxMultiplier || multiplier < CollectionManager.MinMultiplier) return QuickQuit("Your multiplier is out of range. Use a value between " + CollectionManager.MinMultiplier + "-" + CollectionManager.MaxMultiplier, true); //Oops, make sure we're not already using the chance calculator thread if (chanceSimulator.IsBusy) return QuickQuit("The chance calculator is busy right now."); //Calculate the chance on a background thread else chanceSimulator.RunWorkerAsync(Tuple.Create(myUID, multiplier)); return new List<JSONObject>(); } #endregion //How much do you have of item (given) #region amount //match = Regex.Match(message, @"^\s*/cgameamount\s+([a-zA-Z][0-9])\s*$"); else if (cmd == "cgameamount") { SpecialPoint point = SpecialPoint.Parse(command.Arguments[0]); if (!CollectionManager.ValidPoint(point)) return QuickQuit("That item is out of range.", true); return QuickQuit("You have " + collectors[myUID].Inventory[point] + " of item " + CollectionSymbols.GetPointAndSymbol(point)); } #endregion //Compare your inventory to another's #region compare //match = Regex.Match(message, @"^\s*/cgamecompare\s+(.+)\s*$"); else if (cmd == "cgamecompare") { //Generic error (shouldn't happen, but just in case!) if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } //Oops, the user entered the wrong user if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); if (player.UID == myUID) return QuickQuit("You can't compare with yourself!", true); //Get the unique journal entries List<SpecialPoint> myUnique, theirUnique; GetUnique(myUID, player.UID, out myUnique, out theirUnique); string output = "Note: Only the top 5 are shown, so there may be more.\nOnly items that you actually have in your inventory are shown\n-Your unique items are: "; //List out items that only you have for (int i = 0; i < 5; i++) if (i < myUnique.Count) output += CollectionSymbols.GetPointAndSymbol(myUnique[i]) + " "; output += "\n-" + player.Username + " has these unique items: "; //List out items that only the other guy has for (int i = 0; i < 5; i++) if (i < theirUnique.Count) output += CollectionSymbols.GetPointAndSymbol(theirUnique[i]) + " "; return QuickQuit(output); } #endregion //Perform a quicktrade with the given user #region quicktrade //match = Regex.Match(message, @"^\s*/cgamequicktrade\s+(.+)\s*$"); else if (cmd == "cgamequicktrade") { if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } //Oops, there is another offer still standing try { if (offer.OfferStanding) return QuickQuit(OfferStanding(offer, users)); } catch { AddError(outputs); return outputs; } //Oops, the user entered the wrong person if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); //Oops, can't trade with yourself! if (myUID == player.UID) return QuickQuit("You can't trade with yourself!", true); //Get the unique journal entries List<SpecialPoint> myUnique, theirUnique; GetUnique(myUID, player.UID, out myUnique, out theirUnique); //Oops, can't have a nice trade because one of you doesn't have any unique items int tradeItems = Math.Min(myUnique.Count, theirUnique.Count); if (tradeItems == 0) return QuickQuit("There cannot be an even trade between you and " + player.Username); myUnique = myUnique.Take(tradeItems).ToList(); theirUnique = theirUnique.Take(tradeItems).ToList(); offer.CreateTrade(myUID, player.UID, myUnique, theirUnique); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = user.Username + " wants to perform a quick-trade with you.\nOffered item".Pluralify(myUnique.Count) + ": " + PrintPointList(myUnique) + "\nDesired item".Pluralify(theirUnique.Count) + ": " + PrintPointList(theirUnique) + "\nYou have " + offer.OfferTimeout + " seconds to decide (/cgameaccept or /cgamedecline). Note that you two will get the items in your journal, but the item is used up in the process." + " You will not get the item in your inventory"; outputs.Add(playerOutput); mainOutput.message = "Your trade of " + PrintPointList(myUnique) + " for " + PrintPointList(theirUnique) + " with " + player.Username + " has been sent! You'll receive a message when they accept or decline"; outputs.Add(mainOutput); return outputs; } #endregion //Sell to player #region sellPlayer else if (cmd == "cgamesell") { if(!GetUserFromArgument(command.Arguments[1], users, out player)) { AddError(outputs); return outputs; } if(player.UID == myUID) return QuickQuit("You can't sell to yourself!", true); //Set up some initial info List<SpecialPoint> offeredItems; int desiredCoins; //Oops, there is another offer still standing if (offer.OfferStanding) return QuickQuit(OfferStanding(offer, users)); //Ugh, bad values if (!int.TryParse(command.Arguments[2], out desiredCoins)) return QuickQuit("Your sell amount is out of bounds", true); //Oops, the user entered the wrong person if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); //Oops, the other user does not have that many coins if (collectors[player.UID].Coins < desiredCoins) return QuickQuit("You don't have " + desiredCoins + " coin".Pluralify(desiredCoins) + " to spend."); //Try to extract the points to sell try { offeredItems = ExtractPoints(command.Arguments[0], user); } catch (Exception e) { return QuickQuit(e.Message, true); } //Create the sale offer.CreateSale(myUID, player.UID, desiredCoins, offeredItems); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = user.Username + " has offered to sell you " + PrintPointList(offer.SellerItems) + " for " + offer.BuyerCoins + " coin".Pluralify(offer.BuyerCoins) + ".\nYou have " + offer.OfferTimeout + " seconds to decide (/cgameaccept or /cgamedecline). Note that you will get the item in your journal, but NOT your inventory."; outputs.Add(playerOutput); mainOutput.message = "Your offer of " + PrintPointList(offer.SellerItems) + " for " + offer.BuyerCoins + " coin".Pluralify(offer.BuyerCoins) + " with " + player.Username + " has been sent! You'll receive a message when they accept or decline"; outputs.Add(mainOutput); return outputs; } #endregion //Buy from player #region buyPlayer else if (cmd == "cgamebuy") { if(!GetUserFromArgument(command.Arguments[1], users, out player)) { AddError(outputs); return outputs; } //Set up some initial info List<SpecialPoint> desiredItems; int offeredCoins; //Oops, there is another offer still standing if (offer.OfferStanding) return QuickQuit(OfferStanding(offer, users), true); //Ugh, bad values if (!int.TryParse(command.Arguments[2], out offeredCoins)) return QuickQuit("Your buy amount is out of bounds", true); //Oops, the user entered the wrong person if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); //Oops, this user does not have that many coins if (collectors[myUID].Coins < offeredCoins) return QuickQuit("You do not have " + offeredCoins + " coin".Pluralify(offeredCoins) + " to spend."); try { desiredItems = ExtractPoints(command.Arguments[0], player); } catch (Exception e) { return QuickQuit(e.Message, true); } //Create the offer offer.CreatePurchase(player.UID, myUID, offeredCoins, desiredItems); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = user.Username + " has offered to buy " + PrintPointList(offer.SellerItems) + " from you for " + offer.BuyerCoins + " coin".Pluralify(offer.BuyerCoins) + ".\nYou have " + offer.OfferTimeout + " seconds to decide (/cgameaccept or /cgamedecline). "; outputs.Add(playerOutput); mainOutput.message = "Your offer of " + offer.BuyerCoins + " coin".Pluralify(offer.BuyerCoins) + " for " + PrintPointList(offer.SellerItems) + " with " + player.Username + " has been sent! You'll receive a message when they accept or decline"; outputs.Add(mainOutput); return outputs; } #endregion //Give away an item #region give else if (cmd == "cgamegive") { if(!GetUserFromArgument(command.Arguments[1], users, out player)) { AddError(outputs); return outputs; } //Set up some initial info //string potentialReceiver = match.Groups[3].Value; List<SpecialPoint> points; try { points = ExtractPoints(command.Arguments[0], user); } catch (Exception e) { return QuickQuit(e.Message, true); } //Oops, the user entered the wrong player if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); PerformGive(myUID, player.UID, points); ModuleJSONObject playerMessage = new ModuleJSONObject(); playerMessage.recipients.Add(player.UID); playerMessage.message = user.Username + " has given you " + PrintPointList(points) + " for free! How nice!"; outputs.Add(playerMessage); mainOutput.message = "You've given away " + PrintPointList(points) + " to " + player.Username + ". You're nice!"; outputs.Add(mainOutput); return outputs; } #endregion //Trade items with another player #region trade else if (cmd == "cgametrade") { //Get the other user if(!GetUserFromArgument(command.Arguments[1], users, out player)) { AddError(outputs); return outputs; } //Oops, there is another offer still standing if (offer.OfferStanding) return QuickQuit(OfferStanding(offer, users)); //Oops, the user entered the wrong person if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); //Oops, can't trade with yourself! if (player.UID == myUID) return QuickQuit("You can't trade with yourself!"); //Get the points you want to give to the other user List<SpecialPoint> myPoints; List<SpecialPoint> theirPoints; try { myPoints = ExtractPoints(command.Arguments[0], user); theirPoints = ExtractPoints(command.Arguments[2], player); } catch (Exception e) { return QuickQuit(e.Message); } offer.CreateTrade(myUID, player.UID, myPoints, theirPoints); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = user.Username + " wants to perform a trade with you.\nOffered item".Pluralify(myPoints.Count) + ": " + PrintPointList(myPoints) + "\nDesired item".Pluralify(theirPoints.Count) + ": " + PrintPointList(theirPoints) + "\nYou have " + offer.OfferTimeout + " seconds to decide (/cgameaccept or /cgamedecline). Note that you two will get the items in your journal, but the item is used up in the process." + " You will not get the item in your inventory"; outputs.Add(playerOutput); mainOutput.message = "Your trade of " + PrintPointList(myPoints) + " for " + PrintPointList(theirPoints) + " with " + player.Username + " has been sent! You'll receive a message when they accept or decline"; outputs.Add(mainOutput); return outputs; } #endregion //Sell all of the given items #region sellall //match = Regex.Match(message, @"^\s*/cgamesellall\s+(([a-zA-Z][0-9]\s*)+)\s*$"); else if (cmd == "cgameshopsell") { //Build up the list of captured points List<SpecialPoint> points; try { points = ExtractPoints(command.Arguments[0], user); } catch (Exception e) { return QuickQuit(e.Message, true); } int totalAmount = 0; //Now for the actual selling foreach (SpecialPoint point in points) { //Get the total amount of that item we can sell int pointAmount = collectors[myUID].Inventory[point]; //totalAmount += pointAmount; //Sell it all for (int i = 0; i < pointAmount; i++) { int sellPrice = CollectionManager.SellPrice(point, collectors[myUID]); collectors[myUID].SellItem(point, sellPrice); totalAmount += sellPrice; } } return QuickQuit("You sold all " + PrintPointList(points) + " for " + totalAmount + " coins."); } #endregion //Sell ALL of the items #region sellallall if (cmd == "cgameshopsellall") //Regex.IsMatch(message, @"^\s*/cgamesellallall\s*$")) { int totalAmount = 0; //Now for the actual selling foreach (SpecialPoint point in collectors[myUID].Inventory.AllItemCounts().Where(x => x.Value > 0).Select(x => x.Key).ToList()) { //Get the total amount of that item we can sell int pointAmount = collectors[myUID].Inventory[point]; //totalAmount += pointAmount; //Sell it all for (int i = 0; i < pointAmount; i++) { int sellPrice = CollectionManager.SellPrice(point, collectors[myUID]); collectors[myUID].SellItem(point, sellPrice); totalAmount += sellPrice; } } return QuickQuit("You sold everything for " + totalAmount + " coins."); } #endregion //Accept a selling offer #region acceptoffer else if (cmd == "cgameaccept") //Regex.IsMatch(message, @"^\s*/cgameaccept\s*$")) { //Pfft, the sale isn't for you! if (!offer.OfferStanding || myUID != offer.Accepter) return QuickQuit("There are no offers for you right now"); string output = ""; if (offer.Type == CollectionOffer.OfferType.Buy || offer.Type == CollectionOffer.OfferType.Sell) { //This variable is used so that only the first item in the sale exchanges money. After that, they're basically a trade bool firstItem = true; foreach (SpecialPoint sellItem in offer.SellerItems) { //Complete the sale collectors[offer.Seller].SellItem(sellItem, (firstItem ? offer.BuyerCoins : 0)); collectors[offer.Buyer].BuyItem(sellItem, (firstItem ? offer.BuyerCoins : 0)); collectors[offer.Buyer].Inventory.UnobtainItem(sellItem); firstItem = false; } output = users[offer.Buyer].Username + " has bought a journal entry for " + PrintPointList(offer.SellerItems) + " from " + users[offer.Seller].Username + " for " + offer.BuyerCoins + " coin".Pluralify(offer.BuyerCoins) + "."; } else if (offer.Type == CollectionOffer.OfferType.Trade) { output = users[offer.Offerer].Username + " gave these items to " + users[offer.Accepter].Username + ": \n"; //Perform the trade foreach (SpecialPoint item in offer.OffererItems) { output += CollectionSymbols.GetPointAndSymbol(item) + " "; collectors[offer.Offerer].SellItem(item, 0); collectors[offer.Accepter].BuyItem(item, 0); collectors[offer.Accepter].Inventory.UnobtainItem(item); } output += "\nAnd got these items in return: \n"; foreach (SpecialPoint item in offer.AccepterItems) { output += CollectionSymbols.GetPointAndSymbol(item) + " "; collectors[offer.Accepter].SellItem(item, 0); collectors[offer.Offerer].BuyItem(item, 0); collectors[offer.Offerer].Inventory.UnobtainItem(item); } } mainOutput.message = output; mainOutput.recipients.Add(offer.Accepter); mainOutput.recipients.Add(offer.Offerer); outputs.Add(mainOutput); //Reset the sell information offer.Reset(); //We done yo. return outputs; } #endregion //Decline a selling offer #region declineoffer else if (cmd == "cgamedecline")//Regex.IsMatch(message, @"^\s*/cgamedecline\s*$")) { //Pfft, the sale isn't for you! if (!offer.OfferStanding || myUID != offer.Accepter) return QuickQuit("There are no offers for you right now"); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.message = user.Username + " has declined the offer"; playerOutput.recipients.Add(offer.Offerer); outputs.Add(playerOutput); mainOutput.message = "You have declined the offer"; outputs.Add(mainOutput); offer.Reset(); return outputs; } #endregion //View your forever statistics (like total coins, total items collected, etc. #region cgameforeverstats else if (cmd == "cgamestats")//Regex.IsMatch(message, @"^\s*/cgamestats\s*$")) { if (collectors[myUID].Stars < 1) return QuickQuit("You must be at least rank 1 to see your permanent collection game stats"); return QuickQuit(collectors[myUID].ForeverStats()); } #endregion #region cgamequery //match = Regex.Match(message, @"^\s*/cgamequery\s+(([a-zA-Z][0-9]\s*)+)\s*$"); if (cmd == "cgamequery")//match.Success) { List<SpecialPoint> points; try { points = ExtractPoints(command.Arguments[0]).Distinct().ToList(); } catch (Exception e) { return QuickQuit(e.Message, true); } return QuickQuit(GetQuery(points, users)); } if(cmd == "cgamequeryall") { List<SpecialPoint> points = collectors[myUID].Journal.Unobtained(); return QuickQuit(GetQuery(points, users)); } #endregion #region cgamelove //match = Regex.Match(message, @"^\s*/cgamelove\s+(.+)\s*$"); else if (cmd == "cgamelove") //match.Success) { if(CheckIfJealous(myUID, out outputs)) return outputs; //Get the other user if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } return PerformLove(user, player); } #endregion #region cgameaddlove //match = Regex.Match(message, @"^\s*/cgameaddlove\s+(.+)\s*$"); else if(cmd == "cgameaddlove")//match.Success) { if(CheckIfJealous(myUID, out outputs)) return outputs; //Get the other user if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); if (myUID == player.UID) return QuickQuit("You can't add yourself to the love list!", true); if (collectors[myUID].GetLovers().Count >= MaxLovers) return QuickQuit("You're already at your love limit (" + MaxLovers + ")"); if (!collectors[myUID].AddLover(player.UID)) return QuickQuit(player.Username + " is already in your love list!"); return QuickQuit("You've added " + player.Username + " to your love list <3"); } #endregion #region cgameremovelove //match = Regex.Match(message, @"^\s*/cgameremovelove\s+(.+)\s*$"); else if (cmd == "cgameremovelove")//match.Success) { if(CheckIfJealous(myUID, out outputs)) return outputs; //Get the other user if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } if (!collectors[myUID].RemoveLover(player.UID)) return QuickQuit(player.Username + " is not in your love list!"); return QuickQuit("You've removed " + player.Username + " from your love list </3"); } #endregion #region cgamelovelist else if (cmd == "cgamelovelist")//Regex.IsMatch(message, @"^\s*/cgamelovelist\s*$")) { if(CheckIfJealous(myUID, out outputs)) return outputs; List<int> lovers = collectors[myUID].GetLovers(); if(lovers.Count == 0) return QuickQuit("There is nobody on your love list ='("); string output = "These are all the people on your love list:"; foreach (int lover in lovers) if(users.ContainsKey(lover)) output += "\n* " + users[lover].Username; return QuickQuit(output); } #endregion #region cgameloveall if (cmd == "cgameloveall")//Regex.IsMatch(message, @"^\s*/cgameloveall\s*$")) { if(CheckIfJealous(myUID, out outputs)) return outputs; List<Tuple<int, int>> giveCounts = new List<Tuple<int,int>>(); List<int> lovers = collectors[myUID].GetLovers().Where(x => collectors.ContainsKey(x) && users.ContainsKey(x)).ToList(); if (lovers.Count == 0) return QuickQuit("There is nobody on your love list ='("); foreach (int lover in lovers) { List<SpecialPoint> myUnique, theirUnique; GetUnique(myUID, lover, out myUnique, out theirUnique); giveCounts.Add(Tuple.Create(lover, myUnique.Count)); } if(giveCounts.Any(x => x.Item2 == 0)) { mainOutput.message = "Love-all skipped: " + string.Join(", ", giveCounts.Where(x => x.Item2 == 0).Select(x => users[x.Item1].Username)) + "\n"; outputs.Add(mainOutput); } foreach (int lover in giveCounts.Where(x => x.Item2 != 0).OrderBy(x => x.Item2).Select(x => x.Item1)) outputs.AddRange(PerformLove(user, users[lover])); return outputs; } #endregion if(cmd == "cgamecheckjealousy") { if(CheckIfJealous(myUID, out outputs)) return outputs; var canSteal = GetJealousy(myUID); return QuickQuit("If you tap into the darkness in your twisted heart now, you'll get " + canSteal.Count + " item".Pluralify(canSteal.Count) + " plus " + JealousyCoins * users.Count(x => x.Value.LoggedIn) + " coins (1000 coins for each logged in user)"); } if(cmd == "cgamejealousy") { if(CheckIfJealous(myUID, out outputs)) return outputs; Dictionary<SpecialPoint, int> gonnaSteal = GetJealousy(myUID); HashSet<int> usersToInform = new HashSet<int>(); if(gonnaSteal.Count == 0) return QuickQuit("Your jealousy couldn't change the fact that nobody had any items you needed"); foreach(KeyValuePair<SpecialPoint, int> steal in gonnaSteal) { PerformGive(steal.Value, myUID, new List<SpecialPoint> { steal.Key }); usersToInform.Add(steal.Value); } double multiplier = 0.5 + 1.5 * collectors.ToList().OrderBy(x => x.Value.Score()).Select(x => x.Key).ToList().IndexOf(myUID) / (double)collectors.Count; collectors[myUID].JealousyPerformed(gonnaSteal.Count, multiplier); foreach(int userID in usersToInform) { ModuleJSONObject userOutput = new ModuleJSONObject(); int itemCount = gonnaSteal.Count(x => x.Value == userID); userOutput.message = user.Username + " took " + itemCount + " item".Pluralify(itemCount) + " from you!"; userOutput.recipients.Add(userID); outputs.Add(userOutput); } int getCoins = JealousyCoins * users.Count(x => x.Value.LoggedIn); collectors[myUID].GetCoins(getCoins); //WarningJSONObject warnOutput = new WarningJSONObject(); mainOutput.message = "In a fit of jealousy, " + user.Username + " used the darkness in their twisted heart to " + "generate " + getCoins + " coins and steal " + gonnaSteal.Count + " item".Pluralify(gonnaSteal.Count) + " from unsuspecting users. 8(>_<)8"; mainOutput.broadcast = true; outputs.Add(mainOutput); return outputs; } if(cmd == "cgamehug") { if(CheckIfJealous(myUID, out outputs)) return outputs; //Get the other user if(!GetUserFromArgument(command.Arguments[0], users, out player)) { AddError(outputs); return outputs; } if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); if(myUID == player.UID) return QuickQuit("You can't hug yourself!", true); if(CollectionManager.PerformHug(collectors, myUID, player.UID, JealousyTime)) { ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = "You were hugged by " + user.Username + ". The darkness in your heart receded a bit!"; mainOutput.message = "You gave " + player.Username + " a hug and cheered them up a bit!"; outputs.Add(mainOutput); outputs.Add(playerOutput); return outputs; } else { ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = "You were hugged by " + user.Username + ". " + HugSayings[localRandom.Next(HugSayings.Count)]; mainOutput.message = "You gave " + player.Username + " a hug. What a nice person!"; outputs.Add(mainOutput); outputs.Add(playerOutput); return outputs; } } } catch(Exception e) { ModuleJSONObject error = new ModuleJSONObject(); error.broadcast = true; error.message = "The CGAME module has encountered an unknown error. Please tell staff\n\n" + "Error message: " + e.ToString(); return new List<JSONObject> { error }; } return new List<JSONObject>(); }
public List<JSONObject> QuickQuit(string message, bool warning = false, bool safe = true) { if (warning) { WarningJSONObject output = new WarningJSONObject(); output.message = message; return new List<JSONObject> { output }; } else { ModuleJSONObject output = new ModuleJSONObject(); output.message = message; output.safe = safe; return new List<JSONObject> { output }; } }
public List<JSONObject> PerformLove(UserInfo user, UserInfo player) { List<JSONObject> outputs = new List<JSONObject>(); if (CheckIfJealous(player.UID, out outputs)) return QuickQuit("The intense dark aura surrounding " + player.Username + " prevents you from loving them :'("); //Oops, the user entered the wrong player if (!collectors.ContainsKey(player.UID)) return QuickQuit(NotAPlayer(player)); List<SpecialPoint> myUnique, theirUnique; GetUnique(user.UID, player.UID, out myUnique, out theirUnique); if (myUnique.Count == 0) return QuickQuit("It was a nice gesture, but you don't have any unique items to give to " + player.Username + "."); PerformGive(user.UID, player.UID, myUnique); collectors[user.UID].LoveGiven(myUnique.Count); collectors[player.UID].GotLoved(myUnique.Count); ModuleJSONObject playerOutput = new ModuleJSONObject(); playerOutput.recipients.Add(player.UID); playerOutput.message = user.Username + " generously gave you " + myUnique.Count + " item".Pluralify(myUnique.Count) + " - " + PrintPointList(myUnique); outputs.Add(playerOutput); ModuleJSONObject mainOutput = new ModuleJSONObject(); mainOutput.message = "You generously gave " + myUnique.Count + " item".Pluralify(myUnique.Count) + " to " + player.Username + " - " + PrintPointList(myUnique); outputs.Add(mainOutput); return outputs; }