protected virtual bool CheckAndHandleCooldown(CommandMatch cmd, IChannelMessageEventArgs args) { if (Config.CooldownUpperBoundary < 0) { // the cooldown feature is not being used return(false); } CooldownState cdState; if (!ChannelToCooldown.TryGetValue(args.Channel, out cdState)) { cdState = new CooldownState(); ChannelToCooldown[args.Channel] = cdState; } cdState.CooldownValue += Config.CooldownPerCommandUsage; bool coolingDown = (cdState.CooldownTriggered) ? (cdState.CooldownValue > 0) : (cdState.CooldownValue > Config.CooldownUpperBoundary); if (coolingDown) { cdState.CooldownTriggered = true; string cdAnswer = Config.CooldownAnswers[ChosenRNG(cmd).Next(Config.CooldownAnswers.Count)]; ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: {1}", args.SenderNickname, cdAnswer); return(true); } return(false); }
protected virtual void HandleRegexCountCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { var counterName = (string)cmd.Arguments[0]; var nick = (string)cmd.Arguments[1]; string regexString = ((string)cmd.Arguments[2]).Trim(); Counter counter = Config.Counters.FirstOrDefault(c => c.CommandName == counterName); if (counter == null) { ConnectionManager.SendChannelMessage(msg.Channel, $"{msg.SenderNickname}: Unknown counter '{counterName}'"); return; } Regex regex; try { regex = new Regex(regexString, RegexOptions.Compiled); } catch (ArgumentException ae) { ConnectionManager.SendChannelMessage(msg.Channel, $"{msg.SenderNickname}: Invalid regex: {ae.Message}"); return; } TryToMatch(counter, msg.Channel, msg.SenderNickname, messageSubstring: null, messageRegex: regex); }
protected virtual void HandleProverbCommand(CommandMatch cmd, IChannelMessageEventArgs args) { var client = new HttpClient { Timeout = TimeSpan.FromSeconds(Config.TimeoutSeconds) }; using (var request = new HttpRequestMessage(HttpMethod.Get, Config.ProverbURI)) { var htmlDoc = new HtmlDocument(); using (var response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).SyncWait()) using (Stream responseStream = response.Content.ReadAsStreamAsync().SyncWait()) { htmlDoc.Load(responseStream); } string proverb = htmlDoc.DocumentNode .SelectSingleNode(Config.NodeSelector) ?.InnerText; if (proverb != null) { ConnectionManager.SendChannelMessage(args.Channel, $"{args.SenderNickname}: {proverb}"); } } }
private void HandleChannelAka([NotNull] CommandMatch cmd, [NotNull] IChannelMessageEventArgs e) { ActuallyHandleChannelOrQueryAka( cmd, e, txt => ConnectionManager.SendChannelMessage(e.Channel, $"{e.SenderNickname}: {txt}") ); }
protected virtual void HandleTopGratefulCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { List <NicknameAndCount> top; using (var ctx = GetNewContext()) { top = ctx.ThanksEntries .Where(te => !te.Deleted) .GroupBy(te => te.ThankerLowercase, (thanker, thanksEntries) => new NicknameAndCount { Nickname = thanker, Count = thanksEntries.Count() }) .OrderByDescending(teg => teg.Count) .Take(Config.MostThankedCount) .ToList() ; } ConnectionManager.SendChannelMessageFormat( msg.Channel, "{0}: {1}", msg.SenderNickname, top.Select(NicknameAndCountString).StringJoin(", ") ); }
protected virtual void HandleTelCommand(CommandMatch cmd, IChannelMessageEventArgs args) { string telNumber = ((string)cmd.Arguments[0]); if (telNumber.Length > 0) { // remove leading space telNumber = telNumber.Substring(1); } var ret = new StringBuilder(telNumber.Length); foreach (char c in telNumber) { char target; if (TelNoDictionary.TryGetValue(c, out target)) { ret.Append(target); } else { ret.Append(c); } } ConnectionManager.SendChannelMessage(args.Channel, ret.ToString()); }
protected virtual void HandlePassCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.UnoChannel) { return; } lock (TurnLock) { if (CurrentPlayer.Nick != msg.SenderNickname) { ConnectionManager.SendChannelMessageFormat( Config.UnoChannel, "It's not your turn, {0}.", msg.SenderNickname ); return; } if (!DrewLast) { ConnectionManager.SendChannelMessageFormat( Config.UnoChannel, "You have to draw first, {0}.", msg.SenderNickname ); return; } // skip to the next player AdvanceToNextPlayer(); } }
protected virtual void HandleChannelMessage(object sender, IChannelMessageEventArgs args, MessageFlags flags) { if (Config.CooldownUpperBoundary < 0) { // the cooldown feature is not being used return; } CooldownState cdState; if (!ChannelToCooldown.TryGetValue(args.Channel, out cdState)) { cdState = new CooldownState(); ChannelToCooldown[args.Channel] = cdState; } if (cdState.CooldownValue > 0) { --cdState.CooldownValue; if (cdState.CooldownValue == 0) { cdState.CooldownTriggered = false; } } }
protected virtual void HandleBaseNickCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { string channel = msg.Channel; string requestor = msg.SenderNickname; var whichNick = (string)cmd.Arguments[0]; using (var ctx = GetNewContext()) { var baseNick = FindBaseNickFor(whichNick, ctx); if (baseNick == null) { ConnectionManager.SendChannelMessage( channel, $"{requestor}: I can't find the nickname {whichNick}." ); } else { ConnectionManager.SendChannelMessage( channel, $"{requestor}: The base nickname for {whichNick} is {baseNick}." ); } } }
protected virtual void HandleIKnewThatChannelCommand(CommandMatch cmd, IChannelMessageEventArgs args) { string senderLower = (ConnectionManager.RegisteredNameForNick(args.SenderNickname) ?? args.SenderNickname) .ToLowerInvariant(); string keywordLower = ((string)cmd.Arguments[0]).ToLowerInvariant(); using (var ctx = GetNewContext()) { IKnewThatEntry matchingEntry = ctx.Entries .FirstOrDefault(e => e.AuthorLowercase == senderLower && e.KeywordLowercase == keywordLower); if (matchingEntry == null) { ConnectionManager.SendChannelMessage( args.Channel, $"{args.SenderNickname}: No, you didn't!" ); return; } DateTimeOffset timestampLocal = matchingEntry.Timestamp.ToLocalTime(); ConnectionManager.SendChannelMessage( args.Channel, $"I confirm that on {timestampLocal:yyyy-MM-dd} at {timestampLocal:HH:mm:ss}, {args.SenderNickname} knew the following: {matchingEntry.Message}" ); ctx.Entries.Remove(matchingEntry); ctx.SaveChanges(); } }
protected virtual void HandleAddQuoteCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { string normalizedNick = ConnectionManager.RegisteredNameForNick(msg.SenderNickname) ?? msg.SenderNickname; using (var ctx = GetNewContext()) { var newFreeFormQuote = new Quote { Timestamp = DateTime.Now.ToUniversalTimeForDatabase(), Channel = msg.Channel, Author = normalizedNick, MessageType = "F", Body = (string)cmd.Arguments[0] }; ctx.Quotes.Add(newFreeFormQuote); ctx.SaveChanges(); LastQuoteIDs[msg.Channel] = newFreeFormQuote.ID; } ConnectionManager.SendChannelMessage( msg.Channel, "Done." ); // invalidate these ShuffledAnyQuotes = null; ShuffledBadQuotes = null; ShuffledGoodQuotes = null; }
protected virtual void HandleBotTestCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.UnoChannel) { return; } lock (TurnLock) { BotTestCount = (long)cmd.Arguments[0]; ConnectionManager.SendChannelMessageFormat( Config.UnoChannel, "{0} engaged bot test mode; {1} games left!", msg.SenderNickname, BotTestCount ); // prepare a game PrepareGame(); // trigger bot joinage ConnectionManager.SendChannelMessage(Config.UnoChannel, "?join"); // wait for bot joinage BotTestJoinRequested = DateTime.UtcNow; } }
private void HandleWDYTICommandInChannel(CommandMatch cmd, IChannelMessageEventArgs msg) { HandleMessage( (string)cmd.Arguments[0], body => ConnectionManager.SendChannelMessage(msg.Channel, $"{msg.SenderNickname}: {body}") ); }
protected virtual void HandleAnyChannelMessage(object sender, IChannelMessageEventArgs e, MessageFlags flags) { if (!Config.ChannelsPatterns.ContainsKey(e.Channel)) { // don't police this channel return; } IEnumerable <PuntPattern> relevantPatterns = Config.CommonPatterns; IEnumerable <PuntPattern> channelPatterns = Config.ChannelsPatterns[e.Channel]; if (channelPatterns != null) { relevantPatterns = relevantPatterns.Concat(channelPatterns); } string normalizedNick = ConnectionManager.RegisteredNameForNick(e.SenderNickname) ?? e.SenderNickname; foreach (PuntPattern pattern in relevantPatterns) { if (!AnyMatch(normalizedNick, pattern.NickPatterns)) { // wrong user continue; } if (AnyMatch(normalizedNick, pattern.NickExceptPatterns)) { // whitelisted user continue; } if (pattern.ChancePercent.HasValue) { int val = Randomizer.Next(100); if (val >= pattern.ChancePercent.Value) { // luck is on their side continue; } } if (!AnyMatch(e.Message, pattern.BodyPatterns)) { // no body match continue; } if (AnyMatch(e.Message, pattern.BodyExceptPatterns)) { // body exception continue; } // match! kick 'em! ConnectionManager.KickChannelUser(e.Channel, e.SenderNickname, pattern.KickMessage); return; } }
protected virtual void HandleDealCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.UnoChannel) { return; } lock (TurnLock) { switch (CurrentGameState) { case GameState.NoGame: Logger.LogDebug("{Nickname} is trying to deal no game", msg.SenderNickname); return; default: Logger.LogError("invalid game state when trying to add player to game"); return; case GameState.Preparation: case GameState.InProgress: // continue below break; } DealGame(); } }
protected virtual void HandleChannelMessageOrAction(object sender, IChannelMessageEventArgs e, MessageFlags flags) { BounceCriterion crit = InterestingCriterion(e.SenderNickname, channel: null); if (crit != null && crit.ForgetOnChannelMessage) { RelevantJoins.RemoveAll(j => j.Nickname == e.SenderNickname); } }
protected virtual void HandleNewCommand(CommandMatch cmd, IChannelMessageEventArgs message) { if (!EnsureOp(message)) { return; } var criterionName = (string)cmd.Arguments[0]; string detectionRegexString = ((string)cmd.Arguments[1]).Trim(); try { RegexCache.GetOrAdd(detectionRegexString); } catch (ArgumentException) { ConnectionManager.SendChannelMessage(message.Channel, $"{message.SenderNickname}: Invalid regular expression."); return; } using (var ctx = GetNewContext()) { // see if a criterion already matches Criterion crit = ctx.Criteria .FirstOrDefault(c => c.Name == criterionName && c.Channel == message.Channel); if (crit == null) { // create a new criterion crit = new Criterion { Name = criterionName, Channel = message.Channel, DetectionRegex = detectionRegexString, Enabled = true }; } else if (crit.Enabled) { ConnectionManager.SendChannelMessage( message.Channel, $"{message.SenderNickname}: That criterion name is already in use." ); return; } else { // modify the existing criterion and re-enable it crit.DetectionRegex = detectionRegexString; crit.Enabled = true; } ctx.SaveChanges(); // update the cache Dictionary <string, long> commandsIDs = ObtainCommandCacheForChannel(message.Channel); commandsIDs[crit.Name] = crit.ID; } }
protected virtual void HandleStopTriviaCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.TriviaChannel) { return; } StopGame(); }
protected void HandleAutoLinkInfoCommand(CommandMatch cmd, IChannelMessageEventArgs args) { var senderUsername = ConnectionManager.RegisteredNameForNick(args.SenderNickname); if (senderUsername == null) { ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: You must be registered to use this feature.", args.SenderNickname); return; } bool removeSubscription = (cmd.CommandName == "noautolinkinfo"); using (var ctx = GetNewContext()) { var currentSub = ctx.OptedInUsers.FirstOrDefault(u => u.UserName == senderUsername); if (removeSubscription) { if (currentSub == null) { ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: You are not subscribed to auto link info.", args.SenderNickname); } else { Logger.LogInformation( "{Nickname} ({Username}) is unsubscribing from auto link info", args.SenderNickname, senderUsername ); ctx.OptedInUsers.Remove(currentSub); ctx.SaveChanges(); ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: You have been unsubscribed from auto link info.", args.SenderNickname); } } else { // add subscription if (currentSub == null) { Logger.LogInformation( "{Nickname} ({Username}) is subscribing to auto link info", args.SenderNickname, senderUsername ); ctx.OptedInUsers.Add(new OptedInUser { UserName = senderUsername }); ctx.SaveChanges(); ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: You are now subscribed to auto link info.", args.SenderNickname); } else { ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: You are already subscribed to auto link info.", args.SenderNickname); } } } }
protected virtual void HandleChannelAction(object sender, IChannelMessageEventArgs e, MessageFlags flags) { if (flags.HasFlag(MessageFlags.UserBanned)) { return; } // remember RememberMessage(e.Channel, new LastMessage(LastMessageType.ChannelAction, e.SenderNickname, e.Message)); }
protected virtual void LinksAction(IChannelMessageEventArgs args, MessageFlags flags, IList <Uri> links) { // respond? if (Config.AutoShowLinkInfo || args.Message.StartsWith(LinkCommandPrefix)) { foreach (var linkAndInfo in links.Select(ObtainLinkInfo)) { PostLinkInfoToChannel(linkAndInfo, args.Channel); } } }
protected virtual void HandleChannelMessage(object sender, IChannelMessageEventArgs args, MessageFlags flags) { if (!Config.Channels.Contains(args.Channel)) { // wrong channel return; } ProcessPotentialHighlight(args); ProcessPendingRetributions(); }
protected virtual void HandleYesNoCommand(CommandMatch cmd, IChannelMessageEventArgs args) { if (CheckAndHandleCooldown(cmd, args)) { return; } string yesNoAnswer = Config.YesNoAnswers[ChosenRNG(cmd).Next(Config.YesNoAnswers.Count)]; ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: {1}", args.SenderNickname, yesNoAnswer); }
protected virtual void HandleRollCommand(CommandMatch cmd, IChannelMessageEventArgs args) { var rolls = (List <Match>)cmd.Arguments[0]; var diceGroups = new List <DiceGroup>(); foreach (Match rollMatch in rolls) { var diceGroup = ObtainDiceGroup(rollMatch, args.Channel, args.SenderNickname); if (diceGroup == null) { // error occurred and reported; bail out return; } diceGroups.Add(diceGroup); } if (diceGroups.Count > Config.MaxRollCount) { ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: Too many rolls.", args.SenderNickname); return; } // special-case 2d1 if (diceGroups.Count == 1 && diceGroups[0].DieCount == 2 && diceGroups[0].SideCount == 1 && diceGroups[0].AddValue == 0) { ConnectionManager.SendChannelAction(args.Channel, "rolls its eyes"); return; } Random rng = ChosenRNG(cmd); var allRolls = new List <string>(); foreach (var diceGroup in diceGroups) { var theseRolls = new List <string>(diceGroup.DieCount); for (int i = 0; i < diceGroup.DieCount; ++i) { if (diceGroup.SideCount == 1 && Config.ObstinateAnswers.Count > 0) { // special case: give an obstinate answer instead since a 1-sided toss has an obvious result string obstinateAnswer = Config.ObstinateAnswers[rng.Next(Config.ObstinateAnswers.Count)]; theseRolls.Add(obstinateAnswer); } else { long roll = rng.Next(diceGroup.SideCount) + 1 + diceGroup.AddValue; theseRolls.Add(roll.ToString(CultureInfo.InvariantCulture)); } } allRolls.Add(theseRolls.StringJoin(" ")); } ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: {1}", args.SenderNickname, allRolls.StringJoin("; ")); }
protected virtual void HandleWeatherCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { string location = ((string)cmd.Arguments[0]).Trim(); if (location.Length == 0) { location = Config.DefaultLocation; } GetWeatherForLocation(location, msg.Channel, msg.SenderNickname, showLocName: cmd.CommandName == "weather"); }
protected virtual void HandleLeaveCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.UnoChannel) { return; } lock (TurnLock) { RemovePlayerFromGame(msg.SenderNickname); } }
protected virtual bool EnsureOp(IChannelMessageEventArgs message) { ChannelUserLevel level = ConnectionManager.GetChannelLevelForUser(message.Channel, message.SenderNickname); if (level < ChannelUserLevel.HalfOp) { ConnectionManager.SendChannelMessage(message.Channel, $"{message.SenderNickname}: You need to be a channel operator."); return(false); } return(true); }
protected virtual void HandleStartTriviaCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { if (msg.Channel != Config.TriviaChannel) { return; } if (GameState == null) { StartGame(); } }
protected virtual void HandleChannelMessage(object sender, IChannelMessageEventArgs args, MessageFlags flags) { if (flags.HasFlag(MessageFlags.UserBanned)) { return; } if (args.Channel != Config.CasinoChannel) { return; } bool botJoin = false; if (args.Message.Trim() == "?join") { // "?join" botJoin = true; } else { string[] bits = args.Message.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if ( bits.Length >= 2 && bits[0] == "?join" && bits.Skip(1).Any(b => b.Equals(ConnectionManager.MyNickname, StringComparison.OrdinalIgnoreCase)) ) { // "?join MyBot" or "?join ThisBot ThatBot MyBot" botJoin = true; } } if (botJoin) { ConnectionManager.SendChannelMessage(args.Channel, ".botjoin"); ConnectionManager.SendChannelMessage(args.Channel, ".grules"); } // FIXME: these should be JSON events if (string.Equals(args.SenderNickname, Config.GameMasterNickname, StringComparison.OrdinalIgnoreCase)) { if ( args.Message == "Merging the discards back into the shoe and shuffling..." || args.Message == "The dealer's shoe has been shuffled." ) { CardCounter.ShoeShuffled(); DispatchStratDebugMessage($"shoe shuffled -> {CardCounter}"); } } }
protected virtual void HandleIntervalCommand(CommandMatch cmd, IChannelMessageEventArgs msg) { var dateTimeString = (string)cmd.Arguments[0]; DateTime?timestamp = TimeUtil.DateTimeFromString(dateTimeString); if (!timestamp.HasValue) { return; } DateTime timestampUTC = timestamp.Value.ToUniversalTime(); DateTime nowUTC = DateTime.UtcNow; DateTime nowUTCFullSeconds = nowUTC.AddTicks(-(nowUTC.Ticks % TicksPerSecond)); CalendarTimeSpan diff = TimeComparison.CalendarDifference(nowUTCFullSeconds, timestampUTC); var pieces = new List <string>(); MaybeAddUnit(pieces, diff.Years, "year", "years"); MaybeAddUnit(pieces, diff.Months, "month", "months"); MaybeAddUnit(pieces, diff.Days, "day", "days"); MaybeAddUnit(pieces, diff.Hours, "hour", "hours"); MaybeAddUnit(pieces, diff.Minutes, "minute", "minutes"); MaybeAddUnit(pieces, diff.Seconds, "second", "seconds"); string message; if (pieces.Count == 0) { message = "That’s now!"; } else { var messageBuilder = new StringBuilder(); if (pieces.Count > 1) { messageBuilder.Append(string.Join(", ", pieces.Take(pieces.Count - 1))); // 1 year, 2 months, 3 days[ and 4 hours] messageBuilder.Append(" and "); // 1 year, 2 months, 3 days and [4 hours] } messageBuilder.Append(pieces.Last()); messageBuilder.Append(diff.Negative ? " ago." : " remaining."); message = messageBuilder.ToString(); } ConnectionManager.SendChannelMessage(msg.Channel, $"{msg.SenderNickname}: {message}"); }