class BasePublicCommand(BaseCommand): """Same as BaseCommand, but defaults to no ratelimiter.""" DEFAULT_PARAMS = params_lib.MergeParams(BaseCommand.DEFAULT_PARAMS, {'ratelimit': { 'enabled': False }})
class FreeloCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, {'choices': messages.FREELO}) def _Handle(self, *args, **kwargs): return super(FreeloCommand, self)._Handle(*args, **kwargs)
class HCRobCommand(command_lib.BaseCommand): """Like taking candy from a baby.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'target_any': True}) def __init__(self, *args): super(HCRobCommand, self).__init__(*args) self._robbin_hood = coin_lib.Thievery(self._core.store, self._core.bank, self._core.name.lower(), self._core.timezone) @command_lib.HumansOnly('%s is not a crook.') def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User = None, amount_str: Text = '1') -> hype_types.CommandResponse: self._core.last_command = partial(self._Handle, target_user=target_user, amount_str=amount_str) thief = user victim = target_user if victim == thief: return messages.OH_STRING msg_fn = partial(self._Reply, default_channel=channel) amount = self._core.bank.ParseAmount(victim, amount_str, msg_fn) if amount is None: return self._robbin_hood.Rob(thief, victim, amount, msg_fn)
class MissingPingCommand(command_lib.BasePublicCommand): """Flame teammates.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, {'ratelimit': { 'enabled': True, 'interval': 2, 'return_only': True }}) def __init__(self, *args): super(MissingPingCommand, self).__init__(*args) self._last_user = collections.defaultdict(str) self._regex = re.compile(r'^\?+(.*)') @command_lib.MainChannelOnly def _Handle(self, channel, user, message): ping_match = self._regex.match(message) if ping_match: ping_target = ping_match.groups()[0].strip() missing_str = 'enemies are' if ping_target: if util_lib.CanonicalizeName(ping_target) == self._core.nick: ping_target = user missing_str = '%s is' % ping_target self._last_user[channel.id] = ping_target elif self._last_user[channel.id]: missing_str = '%s is' % self._last_user[channel.id] return '\x01ACTION signals that %s missing\x01' % missing_str elif self._core.user_tracker.IsHuman(user): self._last_user[channel.id] = user
class HCResetCommand(command_lib.BaseCommand): # We ratelimit this to 20h per user to prevent unwise fiscal policies. DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'ratelimit': { 'interval': 60 * 60 * 20 }}) @command_lib.MainChannelOnly @command_lib.HumansOnly() def _Handle(self, channel, user, account): if account or coin_lib.IsSubAccount(user): return 'You cannot reset sub-accounts.' cur_balance = self._core.bank.GetBalance(user) if cur_balance > 5000: return ('Surprisingly, I don\'t like to steal hypecoins. ' 'Your balance remains %s') % util_lib.FormatHypecoins(cur_balance) if cur_balance <= 0: self._Reply( channel, '%s has been foolish and unwise with their HypeCoins.' % user) bailout_amount = 5000 - cur_balance if not self._core.bank.ProcessPayment( coin_lib.MINT_ACCOUNT, user, bailout_amount, 'Bailout', self._Reply): return messages.HYPECOIN_MINT_EXHAUSTION_STR
class HypeJackCommand(command_lib.BasePublicCommand): """Redirects input to the HypeJack game.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'ratelimit': { 'enabled': False, }, # Channels where hypejack may be played. 'channels': [], }) def __init__(self, *args, **kwargs): super(HypeJackCommand, self).__init__(*args, **kwargs) # Maps channel ids to their games. self._games = {} # type: Dict[Text, hypejack_lib.Game] for channel in self._params.channels: self._core.interface.Join(channel) self._games[channel.id] = hypejack_lib.Game( channel, self._core, functools.partial(self._Reply, default_channel=channel)) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: if channel.id in self._games: self._games[channel.id].HandleMessage(user, message)
class MissingPingCommand(command_lib.BasePublicCommand): """Flame teammates.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, { 'ratelimit': { 'enabled': True, 'interval': 2, 'return_only': True }, }) def __init__(self, *args): super(MissingPingCommand, self).__init__(*args) self._target = collections.defaultdict(str) self._regex = re.compile(r'^\?+(.*)') def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: ping_match = self._regex.match(message) if ping_match: ping_target = ping_match.groups()[0].strip() missing_str = 'enemies are' if ping_target: if util_lib.CanonicalizeName( ping_target) == self._core.name.lower(): ping_target = user.display_name missing_str = '%s is' % ping_target self._target[channel.id] = ping_target elif self._target[channel.id]: missing_str = '%s is' % self._target[channel.id] return '%s signals that %s missing' % (self._core.params.name, missing_str) elif not user.bot: self._target[channel.id] = user.display_name
class LCSScheduleCommand(command_lib.BaseCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'num_games': 5, 'full_num_games': 10, }) @command_lib.RequireReady('_core.esports') def _Handle(self, channel, user, full, subcommand): include_playoffs = True # Avoid spoilers in spoiler-free channels. if channel.id in FLAGS.spoiler_free_channels: include_playoffs = False subcommand = subcommand.upper() num_games = self._params.num_games if full == 'full': num_games = self._params.full_num_games schedule, subcommand = self._core.esports.GetSchedule( subcommand or 'All', include_playoffs, num_games) lines = ['%s Upcoming Matches' % subcommand] lines.extend(schedule) # Print a disclaimer if we (potentially) omitted any matches. if not include_playoffs and len(schedule) != num_games: lines.append( '(Note: Some matches may be omitted for spoiler reasons)') return lines
class DebugCommand(command_lib.BaseCommand): """Peer into the depths of the bot.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'private_channels_only': True, }) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, subcommand: Text) -> hype_types.CommandResponse: subcommand = subcommand.lower().strip() use_len = re.match(r'^len\((.+)\)$', subcommand) if use_len: subcommand = use_len.group(1) subcommands = subcommand.split('.') obj = self._core while subcommands: token = subcommands.pop(0) available_properties = obj.__dict__ if token in available_properties: try: obj = getattr(obj, token) except AttributeError: logging.warning('Tried to access %s on %s with ap: %s', token, obj, available_properties) return str(len(obj) if use_len else obj) else: return 'Unknown property: %s' % subcommand return str(len(obj) if use_len else obj)
class RatelimitCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, { 'choices': messages.RATELIMIT_MEMES, 'private_channels_only': True })
class HCTransactionsCommand(command_lib.BaseCommand): """See the past movement of money.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'target_any': True}) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User) -> hype_types.CommandResponse: now = arrow.utcnow() recent_transactions = self._core.bank.GetTransactions(target_user) if not recent_transactions: return '%s doesn\'t believe in the HypeCoin economy.' % target_user.display_name responses = [ 'Recent HypeCoin Transactions for %s' % target_user.display_name ] for tx in recent_transactions[:5]: amount = util_lib.FormatHypecoins(tx.amount) if tx.amount < 0: amount = util_lib.Colorize(f'{amount}', 'red') direction = 'to' elif tx.amount > 0: amount = util_lib.Colorize(f'+{amount}', 'green') direction = 'from' else: amount = amount direction = 'with' ago = util_lib.TimeDeltaToHumanDuration( now - arrow.get(tx.create_time.ToSeconds())) responses.append( f'{amount} {direction} {tx.counterparty.display_name} ' f'{ago} ago [{tx.details}]') return responses
class WeatherCommand(command_lib.BaseCommand): """Okay Google, what's the weather?""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'forecast_days': ['Today', 'Tomorrow', 'The next day'], }) _ICON_URL = 'https://darksky.net/images/weather-icons/%s.png' def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, unit: Text, location: Text): unit = unit or self._core.user_prefs.Get(user, 'temperature_unit') unit = unit.upper() location = location or self._core.user_prefs.Get(user, 'location') weather = self._core.weather.GetForecast(location) if not weather: return 'Unknown location.' card = message_pb2.Card(header=message_pb2.Card.Header( title=weather.location, subtitle='%s and %s' % (self._FormatTemp(weather.current.temp_f, unit), weather.current.condition), image={ 'url': self._ICON_URL % weather.current.icon, 'alt_text': weather.current.icon, })) for index, day in enumerate( weather.forecast[:len(self._params.forecast_days)]): card.fields.add( icon_url=self._ICON_URL % day.icon, text='%s: %s - %s %s' % (self._params.forecast_days[index], self._FormatTemp(day.min_temp_f, unit), self._FormatTemp(day.max_temp_f, unit), day.condition)) return card def _FormatTemp(self, temp_f, unit): color = '' if temp_f <= 10: color = 'cyan' elif temp_f <= 32: color = 'blue' elif temp_f >= 100: color = 'red' elif temp_f >= 80: color = 'orange' if unit == 'C': raw_str = '%.1f°C' % ((temp_f - 32) * 5 / 9) elif unit == 'K': raw_str = '%.1fK' % ((temp_f - 32) * 5 / 9 + 273.15) else: raw_str = '%.0f°F' % temp_f return util_lib.Colorize(raw_str, color, irc=False)
class RatelimitCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, {'choices': messages.RATELIMIT_MEMES}) @command_lib.PrivateOnly def _Handle(self, *args, **kwargs): return super(RatelimitCommand, self)._Handle(*args, **kwargs)
class RageCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, {'choices': messages.RAGE_STRINGS}) @command_lib.MainChannelOnly def _Handle(self, *args, **kwargs): return super(RageCommand, self)._Handle(*args, **kwargs)
class MemeCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, { 'choices': [ 'Cake, and grief counseling, will be available at the ' 'conclusion of the test.' ], })
class JackpotCommand(command_lib.BaseCommand): """Runs a daily Jackpot.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { # Time to settle lottery [hour, minute, second]. 'lottery_time': [12, 0, 0], # Warning times in seconds before lottery_time. 'warnings': [60, 3600], }) def __init__(self, *args): super(JackpotCommand, self).__init__(*args) self._game = vegas_game_lib.LotteryGame(self._core.bets) self._core.betting_games.append(self._game) lotto_time = util_lib.ArrowTime(*self._params.lottery_time, tz=self._core.timezone) self._core.scheduler.DailyCallback( lotto_time, self._LotteryCallback, _jitter=10) for warning_sec in self._params.warnings: warning_offset = timedelta(seconds=warning_sec) warning_time = lotto_time - warning_offset self._core.scheduler.DailyCallback( warning_time, self._LotteryWarningCallback, warning_offset, _jitter=0) @command_lib.MainChannelOnly def _Handle(self, channel, unused_user): pool = self._core.bets.LookupBets(self._game.name, resolver=self._core.nick) jackpot, item = self._game.ComputeCurrentJackpot(pool) responses = ['Current jackpot is %s and a(n) %s' % ( util_lib.FormatHypecoins(jackpot), item.human_name)] for bet_user, user_bets in pool.items(): for bet in user_bets: responses.append(u'- %s, %s' % (bet_user, self._game.FormatBet(bet))) return responses def _LotteryCallback(self): logging.info('Running lottery callback.') msg_fn = partial(self._Reply, default_channel=self._core.default_channel) self._core.bets.SettleBets(self._game, self._core.nick, msg_fn) @command_lib.DefaultMainChannelOnly def _LotteryWarningCallback(self, remaining=None): logging.info('Running lottery warning callback.') warning_str = '' if remaining is not None: warning_str += 'The lottery winner will be drawn in %s! ' % ( util_lib.TimeDeltaToHumanDuration(remaining)) pool = self._core.bets.LookupBets(self._game.name, resolver=self._core.nick) coins, item = self._game.ComputeCurrentJackpot(pool) warning_str += 'Current jackpot is %s and a(n) %s' % ( util_lib.FormatHypecoins(coins), item.human_name) self._Reply(self._core.default_channel, warning_str)
class StoryCommand(command_lib.BasePublicCommand): """Story time with Uncle HypeBot.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, { # Each story is a series of lines, alternating between hypebot and any # user. The user may also say 'tell me more' to advance. # This param is left as a dict so overrides can only replace existing # stories or add new ones. 'stories': { # The default story tells the creation of hypebot. 'hypebot': [ 'In the beginning, the hypebot was created.', 'what happened next?', 'HypeBot created dank memes.' ], }, # Amount of time that user has to respond in order to progress story. 'timeout_sec': 30, # Phrases the user can say in case they don't know their line. 'continue_msgs': [ 'tell me more', '...', ], }) def __init__(self, *args): super(StoryCommand, self).__init__(*args) self._stories = self._params.stories.AsDict() self._probs = [] # Store active story keyed on channel id. self._active_stories = {} def _Handle(self, channel, user, message): message = message.lower() t = time.time() story = self._active_stories.get(channel.id) if story and t - story.time > self._params.timeout_sec: del self._active_stories[channel.id] story = None if story and (message == self._stories[story.name][story.line] or message in self._params.continue_msgs): if story.line + 2 < len(self._stories[story.name]): self._active_stories[channel.id] = _StoryProgress( story.name, t, story.line + 2) else: del self._active_stories[channel.id] return self._stories[story.name][story.line + 1] elif not story and message == '%s, tell me a story' % self._core.nick: story_name = util_lib.GetWeightedChoice(list(self._stories.keys()), self._probs) self._active_stories[channel.id] = _StoryProgress(story_name, t, 1) return self._stories[story_name][0]
class MemeCommand(command_lib.TextCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, { 'choices': ['Cake, and grief counseling, will be available at the ' 'conclusion of the test.'], }) def _Handle(self, *args, **kwargs): return super(MemeCommand, self)._Handle(*args, **kwargs)
class DisappointCommand(command_lib.BaseCommand): """Let your son know he is disappoint.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'target_any': True}) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User) -> hype_types.CommandResponse: if target_user.user_id == self._core.name.lower(): return '%s feels its shame deeply' % self._core.params.name return '%s, I am disappoint.' % target_user.display_name
class HCBalanceCommand(command_lib.BaseCommand): """How much cash does a user have?""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'target_any': True}) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User) -> hype_types.CommandResponse: balance = self._core.bank.GetBalance(target_user) return '%s has %s' % (target_user.display_name, util_lib.FormatHypecoins(balance))
class LeaveCommand(command_lib.BaseCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.TextCommand.DEFAULT_PARAMS, {'private_channels_only': True}) def _Handle(self, channel, user, channel_name): self._core.interface.Leave( Channel(id=channel_name, visibility=Channel.PUBLIC, name=channel_name))
class OrRiotCommand(command_lib.BaseCommand): """Angry mob.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'target_any': True}) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User) -> hype_types.CommandResponse: action = ('HYPE' if target_user.display_name.lower() == self._core.name.lower() else 'RIOT') return ('ヽ༼ຈل͜ຈ༽ノ %s OR %s ヽ༼ຈل͜ຈ༽ノ' % (target_user.display_name, action)).upper()
class BaseCommandTestCase(unittest.TestCase): # Set the default bot params (used by core) to something sane for testing. BOT_PARAMS = params_lib.MergeParams( basebot.BaseBot.DEFAULT_PARAMS, { 'interface': { 'type': 'CaptureInterface', }, 'proxy': { # Tests are often run in an environment with no external access, so we # provide a fake Proxy. 'type': 'EmptyProxy', }, 'storage': { 'type': 'MemStore', 'cached_type': 'MemStore', }, 'execution_mode': { # This currently sets the command prefix to `!`. We should figure out # a better long-term solution for the command prefix though since this # can in theory change other behavior within core, but currently # should have no other impacts. 'dev': False, }, 'commands': {}, 'subscriptions': {}, }) @classmethod def setUpClass(cls): super(BaseCommandTestCase, cls).setUpClass() if not hasattr(cls, '_command_cls'): raise AttributeError(( '%s is missing command initializer. All BaseCommandTestCases must' ' be decorated with @ForCommand and given the command they are' ' testing. For example:\n\n@ForCommand(simple_commands.HelpCommand' ')\nclass HelpCommandTest(BaseCommandTestCase):\n ...') % cls.__name__) def setUp(self): super(BaseCommandTestCase, self).setUp() self.interface = interface_factory.CreateFromParams( self.BOT_PARAMS.interface) self.core = hypecore.Core(self.BOT_PARAMS, self.interface) # We disable ratelimiting for tests. self.command = self._command_cls( { 'ratelimit': { 'enabled': False }, 'target_any': True }, self.core)
class AutoReplySnarkCommand(command_lib.BasePublicCommand): """Auto-reply to auto-replies.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, { 'probability': 0.25, # How often to apply extra snark. Note this is only checked when an # auto-reply is emitted. Thus the chance that an extra-snarky reply is # returned is (probability * extra_snark_probability). 'extra_snark_probability': 0.5, }) _AUTO_REPLIES = ( 'Much appreciated', 'Works fine', 'Good point', 'Agreed', 'Ouch', 'Neat!', 'Congrats!', 'Do it', 'Me too', 'Noted!', 'lol', 'Wow, thanks', '💩', '💪', '😬', '🔥', 'Cool story, bro', ) _SNARK_TEMPLATES = ( '{}...', '{} /s', '{} 🙄', '{} 🤔', ) def __init__(self, *args): super(AutoReplySnarkCommand, self).__init__(*args) self._regex = re.compile(r' \((auto|auto-reply|ar)\)$') def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: match = self._regex.search(message) if match and random.random() < self._params.probability: reply = random.choice(self._AUTO_REPLIES) if random.random() < self._params.extra_snark_probability: reply = random.choice(self._SNARK_TEMPLATES).format(reply) return '%s (%s)' % (reply, match.groups()[0])
class SayCommand(command_lib.BasePublicCommand): """Teach hypebot how to respond to certain phrases.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, { # Number of times to repeat phrase. 'repetitions': 5, }) # Key for anyone instead of a specific user. Use all caps to not collide with # normalized usernames. _ANY_SPEAKER = 'ANY_SPEAKER' def __init__(self, *args): super(SayCommand, self).__init__(*args) # Compile regex for efficiency. self._regex = re.compile(r'(?i)when (\S+) says? (.+) you say (.+)$') # Store phrases to repeat keyed on channel, user, and then message. self._phrases = collections.defaultdict( lambda: collections.defaultdict(dict)) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: match = self._regex.search(message) if match: speaker = match.groups()[0].lower() if speaker == 'i': speaker = user.user_id if speaker in ['we', 'anyone', 'someone']: speaker = self._ANY_SPEAKER speaker_phrase = match.groups()[1] hypebot_phrase = match.groups()[2] self._phrases[channel.id][speaker][speaker_phrase] = _SayPhrase( hypebot_phrase, self._params.repetitions) responses = [] for speaker in [user.user_id, self._ANY_SPEAKER]: say = self._phrases[channel.id][speaker].get(message) if say and say.repetitions > 0: responses.append(say.phrase) say = _SayPhrase(say.phrase, say.repetitions - 1) if say.repetitions <= 0: responses.append( 'It\'s an old meme, sir, but it checks out.') del self._phrases[channel.id][speaker][message] else: self._phrases[channel.id][speaker][message] = say # Short circuit so we only get one response. return responses
class LCSStandingsCommand(command_lib.BaseCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'default_region': 'NA', }) @command_lib.RequireReady('_core.esports') def _Handle(self, channel, user, query): # Avoid spoilers in spoiler-free channels. if channel.id in FLAGS.spoiler_free_channels: return 'pls no spoilerino' query = query.split() league = query[0] if query else self._params.default_region bracket = ' '.join(query[1:]) if len(query) > 1 else 'regular' standings = self._core.esports.GetStandings(league, bracket) cards = [] for standing in standings: has_ties = any([team.ties for team in standing['teams']]) format_str = '{0.wins}-{0.losses}' if has_ties: format_str += '-{0.ties}, {0.points}' card = message_pb2.Card( header={ 'title': standing['league'].name, 'subtitle': '%s (%s)' % (standing['bracket'].name, 'W-L-D, Pts' if has_ties else 'W-L'), }, # We will place the top-n teams into the first field separated by # newlines so that we don't have extra whitespace. visible_fields_count=1) team_strs = [('*{0.rank}:* {0.team.abbreviation} (%s)' % format_str).format(team) for team in standing['teams']] # If there are a lot of teams in the bracket, only display the top few. # 6 is chosen since many group stages and Grumble consist of 6 team # brackets. if len(team_strs) > 6: # The number placed into the visible field is n-1 so that we don't only # show a single team in the collapsed section. card.fields.add(text='\n'.join(team_strs[:5])) card.fields.add(text='\n'.join(team_strs[5:])) else: card.fields.add(text='\n'.join(team_strs)) cards.append(card) return cards
class EggHuntCommand(command_lib.BasePublicCommand): """Gotta find them all.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BasePublicCommand.DEFAULT_PARAMS, { 'find_chance': 0.05, }) def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: if random.random() < self._params.find_chance: item = inventory_lib.Create('HypeEgg', self._core, user, {}) self._core.inventory.AddItem(user, item) return '%s found a(n) %s' % (user, item.human_name)
class SameCommand(command_lib.BaseCommand): # Ratelimits n'at are enforced by the called command. DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'ratelimit': { 'enabled': False, }}) @command_lib.MainChannelOnly def _Handle(self, channel, user): if self._core.last_command: self._core.last_command(channel=channel, user=user) # pylint: disable=not-callable else: return 'How can I do what has not been done?'
class BodyCommand(command_lib.BaseCommand): """Body by Jensen.""" DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, { 'target_any': True, }) def _Handle( self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: Optional[user_pb2.User] ) -> hype_types.CommandResponse: if not target_user: target_user = user_pb2.User(display_name='Jensen') return u'Yo, %s, body these fools!' % target_user.display_name
class LCSStandingsCommand(command_lib.BaseCommand): DEFAULT_PARAMS = params_lib.MergeParams( command_lib.BaseCommand.DEFAULT_PARAMS, {'default_region': 'NA'}) @command_lib.RequireReady('_core.esports') def _Handle(self, channel, user, query): # Avoid spoilers in spoiler-free channels. if channel.id in FLAGS.spoiler_free_channels: return 'pls no spoilerino' query = query.upper().split() req_league = query[0] if query else self._params.default_region req_brackets = query[1:] if len(query) > 1 else ['SEASON'] return self._core.esports.GetStandings(req_league, req_brackets)