def _ExtractOverrides(self, raw_message): """Returns nothing, or the overrides parsed for a channel, user, and msg.""" message_regex = re.compile(r'^\[(#?\w+)(?:\|(#?\w+))?\]\s*(.+)') match = message_regex.match(raw_message) if not match: return username = self._params.default_username channel_name = self._params.default_channel.name visibility = channel_pb2.Channel.PUBLIC for i in range(1, 3): user_or_channel = match.group(i) if not user_or_channel: break if user_or_channel.startswith('#'): channel_name = user_or_channel if channel_name.startswith('#sys'): visibility = channel_pb2.Channel.SYSTEM else: username = user_or_channel if username.lower() == channel_name.strip('#').lower(): visibility = channel_pb2.Channel.PRIVATE message = match.group(3) return (channel_pb2.Channel(id=channel_name, visibility=visibility, name=channel_name), user_pb2.User(user_id=username, display_name=username, bot=username.endswith('bot')), message)
def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, message: Text) -> hype_types.CommandResponse: with self._lock: if (self._cookie and time.time() - self._last_time > self._params.timeout_sec): self._ResetSong() line = self._SONG[self._line_num] match = re.match(line.pattern, message) if match: if line.state == 'accusation': if not self._accusor: # No accusor means no current song. if match.groups()[0].lower() != 'who': return self._cookie = match.groups()[1] self._accusor = user self._accused = user_pb2.User( user_id=self._core.name, display_name=self._core.name) elif user == self._accusor and match.groups( )[1] == self._cookie: self._accused = self._core.interface.FindUser( match.groups()[0]) if ((self._AccusorsTurn() and user == self._accusor) or (self._AccusedTurn() and user == self._accused)): self._NextLine(channel)
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
def WhoAll(self): for guild in self._client.guilds: for member in guild.members: self._user_tracker.AddUser( user_pb2.User(user_id=str(member.id), display_name=member.display_name, bot=member.bot))
def setUp(self): super(BaseCoffeeCommandTestCase, self).setUp() self.test_user = user_pb2.User(user_id='test-user', display_name='Tester') self.test_badge = coffee_pb2.Badge( id=0, name='Test Badge', description='This is for being a good tester.') self.test_data = coffee_pb2.CoffeeData( energy=10, beans=[ coffee_pb2.Bean(variety='Robusta', region='Brazil', rarity='rare'), coffee_pb2.Bean(variety='Arabica', region='Honduras', rarity='common'), coffee_pb2.Bean(variety='Liberica', region='Nicaragua', rarity='legendary') ], badges=[self.test_badge.id]) self.core.coffee._SetCoffeeData(self.test_user, self.test_data) # TODO: Figure out how to load badge textproto in third_party. self.core.coffee.badges = {self.test_badge.id: self.test_badge}
def Loop(self): while True: channel = self._params.default_channel user = user_pb2.User(user_id=self._params.default_username, display_name=self._params.default_username) message = input('> ') overrides = self._ExtractOverrides(message) if overrides: channel, user, message = overrides self._on_message_fn(channel, user, message)
def _DistributeToPastVictims(self, msg_fn): """Distribute funds in scholarship account to past victims.""" victim_scores = self._GetPDF('victim') scholarship_balance = self._bank.GetBalance(SCHOLARSHIP_ACCOUNT) self._bank.ProcessPayment( SCHOLARSHIP_ACCOUNT, [user_pb2.User(user_id=v) for v in victim_scores.keys()], scholarship_balance, 'Victim scholarship fund', msg_fn, merchant_weights=victim_scores.values())
def _ParseCommandTarget(self, user: user_pb2.User, target_user: Text, message: Text) -> Optional[user_pb2.User]: """Processes raw target_user into a User class, resolving 'me' to user.""" # An empty target_user defaults to the calling user if target_user.strip() in ('', 'me'): self._core.last_command = partial(self.Handle, message=message) return user real_user = self._core.interface.FindUser(target_user) if self._params.target_any and not real_user: real_user = user_pb2.User(user_id=target_user, display_name=target_user) return real_user
def _RestoreUserEnergy( self, username: Text, tx: Optional[storage_lib.HypeTransaction] = None) -> None: if not tx: return self._store.RunInTransaction(self._RestoreUserEnergy, username) user = user_pb2.User(user_id=username) user_data = self.GetCoffeeData(user, tx) # Min is set such that there is a ~1% chance that a user with no beans ends # up at 0 energy without finding at least one bean. min_energy = int(math.ceil(math.log(0.01, self._params.bean_chance))) max_energy = min_energy * 4 # We allow users to go over the "max" energy, but they will stop # regenerating energy until they fall back below the max. if user_data.energy < max_energy: user_data.energy = max(min_energy, user_data.energy + 3) # Ensure we don't regen over the max. user_data.energy = min(max_energy, user_data.energy) self._SetCoffeeData(user, user_data, tx)
async def on_message(message): # Discord doesn't protect us from responding to ourself. if message.author == self._client.user: return logging.info('Message from: %s - %s#%s - %s', message.author.name, message.author.display_name, message.author.discriminator, message.author.id) user = user_pb2.User(user_id=str(message.author.id), display_name=message.author.display_name) # Discord has DMChannel for single user interaction and GroupChannel for # group DMs outside of traditional TextChannels within a guild. We only # consider the DMChannel (single user) as private to prevent spam in Group # conversations. if isinstance(message.channel, discord.DMChannel): channel = channel_pb2.Channel( id=str(message.channel.id), visibility=channel_pb2.Channel.PRIVATE, name=message.channel.recipient.name) else: channel = channel_pb2.Channel( id=str(message.channel.id), visibility=channel_pb2.Channel.PUBLIC, name=message.channel.name) self._on_message_fn(channel, user, self._CleanContent(message))
def FindUser(self, query): """Override of parent FindUser since users are faked in the terminal.""" return user_pb2.User(display_name=query, user_id=query)
def Rob(self, thief, victim, amount, msg_fn): """Attempt a robbery.""" if amount < 0: msg_fn(None, 'Did you mean !hc gift?') return if victim.user_id in self._protected_peeps: msg_fn(None, 'The Godfather protects his family.') self._bank.ProcessPayment( thief, user_pb2.User(user_id=self._bot_name, display_name=self._bot_name), 500, 'In Soviet Russia, %s steals from you.' % self._bot_name, msg_fn) return victim_balance = self._bank.GetBalance(victim) if victim_balance <= 0: msg_fn(None, 'You cannot milk a dead cow.') return thief_alert = self._GetPDF('thief')[thief.user_id] victim_alert = self._GetPDF('victim')[victim.user_id] offset = self._BASE_BALANCE_PERCENT * (1 - thief_alert - victim_alert) failure_chance = self._Sigmoid(amount / victim_balance, offset) rob_attempt_score = random.random() logging.info('(%s: %0.2f, %s: %0.2f) %s of %s attempt %0.2f >? %0.2f', thief, thief_alert, victim, victim_alert, amount, victim_balance, rob_attempt_score, failure_chance) if rob_attempt_score < failure_chance: self._bank.ProcessPayment( thief, SCHOLARSHIP_ACCOUNT, min(self._bank.GetBalance(thief), amount), 'Victim scholarship fund', msg_fn) self._DistributeToPastVictims(msg_fn) if (rob_attempt_score < failure_chance * thief_alert / (thief_alert + victim_alert + 1e-6)): msg_fn( None, '%s is a known thief and was caught.' % thief.display_name) else: msg_fn( None, '%s is on high alert and caught %s.' % (victim.display_name, thief.display_name)) return # TODO: Fold ProcessPayment into the UpdateScores tx. # We don't worry about the victim having insufficient funds since there is a # 0% chance of stealing 100% of someone's money. if self._bank.ProcessPayment(victim, thief, amount, 'Highway robbery', msg_fn): self._store.RunInTransaction(self._UpdateScores, thief, victim, amount) formatted_amount = util_lib.FormatHypecoins(amount) msg_fn( None, '%s stole %s from %s' % (thief.display_name, formatted_amount, victim.display_name)) # We privmsg the victim to make sure they know who stole their hypecoins. msg_fn( victim, 'You\'ve been robbed! %s stole %s' % (thief.display_name, formatted_amount))
from absl import logging from hypebot.core import schedule_lib from hypebot.core import util_lib from hypebot.data import messages from hypebot.protos import bank_pb2 from hypebot.protos import bet_pb2 from hypebot.protos import user_pb2 import six # pylint: disable=line-too-long # pylint: enable=line-too-long from google.protobuf import json_format # "Accounts" where various transactions end up BOOKIE_ACCOUNT = user_pb2.User(user_id='_hypebank', display_name='HypeBank') FEE_ACCOUNT = BOOKIE_ACCOUNT MINT_ACCOUNT = BOOKIE_ACCOUNT SCHOLARSHIP_ACCOUNT = user_pb2.User(user_id='_hypescholarship', display_name='HypeScholarship') SUBSCRIPTION_ACCOUNT = BOOKIE_ACCOUNT # pyformat: disable HYPECENTS = frozenset([ BOOKIE_ACCOUNT.user_id, FEE_ACCOUNT.user_id, MINT_ACCOUNT.user_id, SCHOLARSHIP_ACCOUNT.user_id, SUBSCRIPTION_ACCOUNT.user_id, ]) # pyformat: enable
from __future__ import print_function from __future__ import unicode_literals import unittest from hypebot import basebot from hypebot import hypecore from hypebot.core import params_lib from hypebot.interfaces import interface_factory from hypebot.protos import channel_pb2 from hypebot.protos import user_pb2 TEST_CHANNEL = channel_pb2.Channel(id='#test', name='Test', visibility=channel_pb2.Channel.PUBLIC) TEST_USER = user_pb2.User(user_id='_test', display_name='user') def ForCommand(command_cls): """Decorator to enable setting the command for each test class.""" def _Internal(test_cls): test_cls._command_cls = command_cls return test_cls return _Internal class BaseCommandTestCase(unittest.TestCase): # Set the default bot params (used by core) to something sane for testing. BOT_PARAMS = params_lib.MergeParams(