Exemplo n.º 1
0
class BasePublicCommand(BaseCommand):
  """Same as BaseCommand, but defaults to no ratelimiter."""

  DEFAULT_PARAMS = params_lib.MergeParams(BaseCommand.DEFAULT_PARAMS,
                                          {'ratelimit': {
                                              'enabled': False
                                          }})
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
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
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
class RatelimitCommand(command_lib.TextCommand):

    DEFAULT_PARAMS = params_lib.MergeParams(
        command_lib.TextCommand.DEFAULT_PARAMS, {
            'choices': messages.RATELIMIT_MEMES,
            'private_channels_only': True
        })
Exemplo n.º 11
0
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
Exemplo n.º 12
0
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)
Exemplo n.º 13
0
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)
Exemplo n.º 14
0
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)
Exemplo n.º 15
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.'
            ],
        })
Exemplo n.º 16
0
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)
Exemplo n.º 17
0
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]
Exemplo n.º 18
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)
Exemplo n.º 19
0
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
Exemplo n.º 20
0
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))
Exemplo n.º 21
0
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))
Exemplo n.º 22
0
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()
Exemplo n.º 23
0
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)
Exemplo n.º 24
0
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])
Exemplo n.º 25
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
Exemplo n.º 26
0
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
Exemplo n.º 27
0
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)
Exemplo n.º 28
0
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?'
Exemplo n.º 29
0
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
Exemplo n.º 30
0
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)