def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: Optional[user_pb2.User] = None): if not target_user: target_user = user coffee_data = self._core.coffee.GetCoffeeData(target_user) card = message_pb2.Card(header=message_pb2.Card.Header( title='%s\'s Coffee Stash:' % target_user.display_name, subtitle='%d energy | %s | %s' % (coffee_data.energy, inflect_lib.Plural(len(coffee_data.beans or []), 'bean'), inflect_lib.Plural(len(coffee_data.badges or []), 'badge'))), visible_fields_count=5) if not coffee_data.beans: card.fields.add(text='A %s flies out of your empty stash.' % random.choice(('moth', 'fly', 'hypebug', 'bee'))) return card beans = sorted(coffee_data.beans, key=self._core.coffee.GetOccurrenceChance) c = 1 for i, bean in enumerate(beans): if i < (len(beans) - 1) and bean == beans[i + 1]: c += 1 else: card.fields.add(text=FormatBean(bean, uppercase=True, count=c)) c = 1 return card
def _Handle(self, channel, user, msg): logging.info('Scrabbling: "%s"', msg) scrabble_msg = ''.join(msg.upper().split()) if not all(c in self._CHAR_TO_POINTS for c in scrabble_msg): return 'Silly human, you can\'t play %s in scrabble.' % msg scrabble_score = sum(self._CHAR_TO_POINTS[c] for c in scrabble_msg) return '%s is worth %s' % (msg, inflect_lib.Plural(scrabble_score, 'point'))
def SettleBets(self, pool, msg_fn, *args, **kwargs): # The lotto is global, so there should only be a single bet for each user pool_value = sum(user_bets[0].amount for user_bets in pool.values()) if not pool_value: return ([], {}) msg_fn( None, 'All 7-11s are closed! %s bet %s on the lottery' % (inflect_lib.Plural(len(pool), 'pleb'), util_lib.FormatHypecoins(pool_value))) coins, item = self.ComputeCurrentJackpot(pool) winning_number = random.randint(1, pool_value) ticket_number = 0 for user, user_bets in pool.items(): num_tickets = user_bets[0].amount ticket_number += num_tickets if ticket_number >= winning_number: msg_fn(user, [ 'You\'ve won %s in the lottery!' % util_lib.FormatHypecoins(coins), ('We\'ve always been such close friends. Can I borrow some money ' 'for rent?') ]) msg_fn( None, '%s won %s and a(n) %s in the lottery!' % (user, util_lib.FormatHypecoins(coins), item.human_name)) return ([(user, coins), (user, item)], {}) return ([], {})
def _Handle(self, channel, user, message): now = arrow.utcnow() for match in self._core.esports.schedule: if channel.id in match['announced']: continue time_until_match = match['time'] - now if time_until_match.days < 0 or time_until_match.seconds < 0: match['announced'][channel.id] = True continue if (time_until_match.days == 0 and time_until_match.seconds < self._params.match_notification_sec): if match.get('playoffs' ) and channel.id in FLAGS.spoiler_free_channels: continue match['announced'][channel.id] = True blue, red = (match.get('blue'), match.get('red')) if blue and red: match_name = '%s v %s' % (blue, red) else: match_name = 'A LCS match' livestream_str = messages.FALLBACK_LIVESTREAM_LINK livestream_link = self._core.esports.GetLivestreamLinks().get( match['id']) if livestream_link: livestream_str = 'Watch at %s' % livestream_link self._core.interface.Topic( self._core.lcs_channel, LCS_TOPIC_STRING % livestream_link) self._core.interface.Notice( channel, u'%s is starting in ~%s. %s and get #Hyped!' % (match_name, inflect_lib.Plural(time_until_match.seconds / 60, 'minute'), livestream_str))
def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User) -> hype_types.CommandResponse: num_users, coins_in_circulation = self._core.bank.GetBankStats( plebs_only=True) return ('There is %s circulating among %s.' % (util_lib.FormatHypecoins(coins_in_circulation), inflect_lib.Plural(num_users, 'pleb')))
def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: user_pb2.User) -> hype_types.CommandResponse: if target_user.display_name.lower() == self._core.name.lower(): return '%s IS the stack' % self._core.name stacks = self._core.hypestacks.GetHypeStacks(target_user) if stacks: return '%s has %s' % (target_user.display_name, inflect_lib.Plural(stacks, 'HypeStack')) else: return '%s isn\'t very hype' % target_user.display_name
def _Handle(self, channel, user, account, me, users_or_games): game_names = {g.name.lower(): g for g in self._core.betting_games} desired_games = set() users = set() if me: users.add(_GetUserAccount(user, account)) for user_or_game in (users_or_games or '').split(): if user_or_game in game_names: desired_games.add(game_names[user_or_game]) elif user_or_game == 'me': users.add(_GetUserAccount(user, account)) else: users.add(_GetUserAccount(user_or_game, account)) query_name = '%s%s%s' % (', '.join(users), ' - ' if users and desired_games else '', ', '.join([g.name for g in desired_games])) # Default behaviors if not specified. if not users: users = set([None]) # This will allow all users in a LookupBets. if not desired_games: desired_games = self._core.betting_games bets = [] bet_total = 0 for game in desired_games: for bet_user in users: bets_by_user = self._core.bets.LookupBets(game.name, bet_user) for u, user_bets in bets_by_user.items(): if account and not coin_lib.IsSubAccount(u, account): continue for bet in user_bets: if len(users) > 1 or users == set([None]): bets.append((bet.amount, '- %s, %s' % (u, game.FormatBet(bet)))) else: bets.append((bet.amount, '- %s' % game.FormatBet(bet))) bet_total += bet.amount bets.sort(key=lambda bet: bet[0], reverse=True) bets = [betstring for _, betstring in bets] if not bets: query_str = '%s has n' % query_name if query_name else 'N' return '%so current bets. Risk aversion is unbecoming' % query_str responses = ['%s current bets [%s, %s]' % (query_name or 'All', inflect_lib.Plural(len(bets), 'bet'), util_lib.FormatHypecoins(bet_total))] if (len(bets) > self._params.num_bets and channel.visibility == Channel.PUBLIC): responses.append('Only showing %d bets, addiction is no joke.' % self._params.num_bets) bets = bets[:self._params.num_bets] responses.extend(bets) return responses
def SettleBets(self, pool, msg_fn, *args, **kwargs): unused_bets = defaultdict(list) winners = defaultdict(int) pool_value = 0 msgs = [] for user, user_bets in pool.items(): winning_teams = [] losing_teams = [] net_amount = 0 for bet in user_bets: lcs_data = bet_pb2.LCSData() bet.data.Unpack(lcs_data) match = self._esports.matches.get(bet.target, {}) logging.info('Game time: %s', match) winner = match.get('winner', None) if winner: logging.info('GambleLCS: %s bet %s for %s and %s won.', user, bet.amount, lcs_data.winner, winner) pool_value += bet.amount if lcs_data.winner == winner: winning_teams.append(winner) winners[user] += bet.amount * 2 net_amount += bet.amount else: losing_teams.append(lcs_data.winner) net_amount -= bet.amount else: logging.info('Unused bet: %s', bet) unused_bets[user].append(bet) if winning_teams or losing_teams: right_snippet = _BuildSymbolSnippet(winning_teams, 'right') wrong_snippet = _BuildSymbolSnippet(losing_teams, 'wrong') if net_amount == 0: summary_snippet = 'breaking even.' else: summary_snippet = 'ending %s %s.' % ( 'up' if net_amount > 0 else 'down', util_lib.FormatHypecoins(abs(net_amount))) user_message = '%s was %s%s%s' % ( user, right_snippet, wrong_snippet, summary_snippet) msgs.append(user_message) if msgs: msg_fn( None, 'LCS match results in! %s bet %s.' % (inflect_lib.Plural( len(msgs), 'pleb'), util_lib.FormatHypecoins(pool_value))) for msg in msgs: msg_fn(None, msg) return (winners.items(), unused_bets)
def _BuildSymbolSnippet(symbols, adj, display_max=4): if not symbols: return '' response_symbols = symbols[:display_max] if len(symbols) > display_max: response_symbols.pop() num_extras = len(symbols) - len(response_symbols) response_symbols.append(inflect_lib.Plural(num_extras, 'other')) if len(response_symbols) == 1: return '%s about %s; ' % (adj, response_symbols[0]) return '%s about %s; ' % (adj, ' and '.join( [', '.join(response_symbols[:-1]), response_symbols[-1]]))
def _PopulatePickBanChampStr(self, champ_str, champ, stats, subcommand, num_games): pb_info = {} pb_info['champ'] = champ pb_info['rate_str'] = subcommand[:-1].lower() pb_info['appear_str'] = '' if subcommand == 'all': pb_info['appear_str'] = '{:4.3g}% pick+ban rate, '.format( (stats['bans'] + stats['picks']) / num_games * 100) # For 'all' we show both pick+ban rate and win rate pb_info['rate_str'] = 'win' per_subcommand_data = { 'ban': { 'rate': stats['bans'] / num_games * 100, 'stat': stats['bans'], 'stat_desc': 'ban', 'include_win_loss': False }, 'pick': { 'rate': stats['picks'] / num_games * 100, 'stat': stats['picks'], 'stat_desc': 'game', 'include_win_loss': True }, 'win': { 'rate': 0 if not stats['picks'] else stats['wins'] / stats['picks'] * 100, 'stat': stats['picks'], 'stat_desc': 'game', 'include_win_loss': True } } pb_info.update(per_subcommand_data[pb_info['rate_str']]) pb_info['stat_str'] = inflect_lib.Plural(pb_info['stat'], pb_info['stat_desc']) pb_info['win_loss_str'] = '' if pb_info['include_win_loss']: pb_info['win_loss_str'] = ', %s-%s' % ( stats['wins'], stats['picks'] - stats['wins']) return champ_str.format(**pb_info)
def _Handle(self, channel: Channel, user: str, stack_user: str) -> hypecore.MessageType: stack_user = stack_user or 'me' normalized_stack_user = util_lib.CanonicalizeName(stack_user) if normalized_stack_user == 'me': self._core.last_command = partial(self._Handle, stack_user=stack_user) normalized_stack_user = user stack_user = user elif normalized_stack_user == self._core.nick: return '%s IS the stack' % self._core.nick stack_user = stack_user.strip() stacks = self._core.hypestacks.GetHypeStacks(normalized_stack_user) stack_msg = '%s isn\'t very hype' % stack_user if stacks: stack_msg = '%s has %s' % (stack_user, inflect_lib.Plural(stacks, 'HypeStack')) return stack_msg
def Champs(self, summoner): """Gets and formats champion mastery data for summoner.""" summoner_id = int(summoner.get('summoner_id', 0)) region = summoner.get('region', DEFAULT_REGION) r = self._rito.ListChampionMasteries(region, summoner_id) if r: logging.info('Got champ mastery data for %s/%d [%s]', region, summoner_id, summoner['summoner']) # Calculate total number of chests received total_chests = sum(1 for x in r.champion_masteries if x.chest_granted) top_champs = [] for champ in r.champion_masteries[:3]: top_champs.append(self._game.champion_id_to_name[str( champ.champion_id)]) top_champ_lvl = r.champion_masteries[0].champion_level chest_verb = '' chest_verb_dict = { (0, 2): 'receiving', (2, 4): 'collecting', (4, 8): 'earning', (8, 16): 'amassing', (16, 32): 'hoarding' } for range_spec, verb in chest_verb_dict.items(): if total_chests in range(*range_spec): chest_verb = verb break if chest_verb: chest_str = '%s %s' % ( chest_verb, inflect_lib.Plural(total_chests, 'chest')) else: chest_str = 'with a boatload of chests (%d)' % total_chests return ( u'{0} is a L{1} {2[0]} main, but sometimes likes to play {2[1]} ' 'and {2[2]}, {3} this season.').format(summoner['summoner'], top_champ_lvl, top_champs, chest_str)
def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, target_user: Optional[user_pb2.User] = None): if not target_user: target_user = user coffee_data = self._core.coffee.GetCoffeeData(target_user) if not coffee_data.badges: return message_pb2.Card(fields=[ message_pb2.Card.Field(text=NO_BADGES_MESSAGE % target_user.display_name) ]) card = message_pb2.Card(header=message_pb2.Card.Header( title='%s\'s Coffee Badges' % target_user.display_name, subtitle=inflect_lib.Plural(len(coffee_data.badges), 'badge')), visible_fields_count=5) # Reverse list so newest badges are shown first for b_id in coffee_data.badges[::-1]: badge = self._core.coffee.badges[b_id] card.fields.add(icon_url=badge.image_url, text='%s: %s' % (badge.name, badge.description)) return card
def _Handle(self, channel: Channel, user: str, stack_amount: str) -> hypecore.MessageType: num_stacks = util_lib.SafeCast(stack_amount, int, 0) if not num_stacks: self._core.bets.FineUser(user, 1, 'You must buy at least one HypeStack.', self._Reply) return hypecoin_amount = self._core.hypestacks.PriceForHypeStacks( user, num_stacks) if not hypecoin_amount: return summary = 'purchase of %s for %s' % (inflect_lib.Plural( num_stacks, 'HypeStack'), util_lib.FormatHypecoins(hypecoin_amount)) purchase_details = { 'num_stacks': num_stacks, 'summary': summary, 'cost': hypecoin_amount } self._core.request_tracker.RequestConfirmation( user, summary, purchase_details, self._core.hypestacks.PurchaseStacks)
def _Handle(self, unused_channel, unused_user, detailed, region): endpoint = 'us' if region: region = region.upper() endpoint = 'states' region = region or 'USA' raw_results = self._core.proxy.FetchJson(self._API_URL + endpoint) logging.info('CovidAPI raw_result: %s', raw_results) if not raw_results: return 'Unknown region, maybe everyone should move there.' state_data = {} if len(raw_results) == 1: state_data = raw_results[0] else: state_data = [ state for state in raw_results if state.get('state') == region ][0] if not state_data: return 'Unknown region, maybe everyone should move there.' # Raw data cases, new_cases = self._ParseResult(state_data, 'positive') tests, new_tests = self._ParseResult(state_data, 'totalTestResults') hospitalized, new_hospitalizations = self._ParseResult( state_data, 'hospitalizedCurrently') ventilators, _ = self._ParseResult(state_data, 'onVentilatorCurrently') icu_patients, _ = self._ParseResult(state_data, 'inIcuCurrently') deaths, new_deaths = self._ParseResult(state_data, 'death') population = self._core.population.GetPopulation(region) if detailed: fields = [] info_field_fn = functools.partial(self._InfoField, population=population) if cases: fields.append( info_field_fn('Confirmed cases', cases, new_cases)) if tests: fields.append( info_field_fn('Tests administered', tests, new_tests, up_is_good=True)) if hospitalized: fields.append( info_field_fn( 'Hospitalized', hospitalized, new_hospitalizations, )) if icu_patients: fields.append(info_field_fn('ICU patients', icu_patients)) if ventilators: fields.append(info_field_fn('Ventilators in use', ventilators)) if deaths: fields.append(info_field_fn('Deaths', deaths, new_deaths)) update_time = state_data.get('dateChecked') or state_data.get( 'lastModified') update_time_str = 'some time' if update_time: update_timedelta = arrow.utcnow() - arrow.get(update_time) update_time_str = util_lib.TimeDeltaToHumanDuration( update_timedelta) fields.append( message_pb2.Card.Field(buttons=[ message_pb2.Card.Field.Button( text='Source', action_url='https://covidtracking.com/') ])) return message_pb2.Card(header=message_pb2.Card.Header( title='%s COVID-19 Statistics' % self._core.population.GetNameForRegion(region), subtitle='Updated %s ago' % update_time_str), fields=fields, visible_fields_count=4) deaths, descriptor = inflect_lib.Plural(deaths, 'death').split() death_str = '{:,} {}'.format(int(deaths), descriptor) cases, descriptor = inflect_lib.Plural( cases, 'confirmed cases').split(maxsplit=1) case_str = '{:,} {}'.format(int(cases), descriptor) tests, descriptor = inflect_lib.Plural(tests, 'test').split() percent_tested = float(tests) / population test_str = '{:,} [{:.1%} of the population] {}'.format( int(tests), percent_tested, descriptor) return '%s has %s (%s) with %s administered.' % ( region or 'The US', case_str, death_str, test_str)
def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User, me: Text, users_or_games: Text) -> hype_types.CommandResponse: game_names = {g.name.lower(): g for g in self._core.betting_games} desired_games = set() users = {} if me: users[user.user_id] = user for user_or_game in (users_or_games or '').split(): if user_or_game in game_names: desired_games.add(game_names[user_or_game]) elif user_or_game == 'me': users[user.user_id] = user else: maybe_user = self._core.interface.FindUser(user_or_game) if maybe_user: users[maybe_user.user_id] = maybe_user query_name = '%s%s%s' % (', '.join( [u.display_name for u in users.values()]), ' - ' if users and desired_games else '', ', '.join([g.name for g in desired_games])) # Default behaviors if not specified. if not users: users = {None: None} # This will allow all users in a LookupBets. if not desired_games: desired_games = self._core.betting_games bets = [] bet_total = 0 for game in desired_games: for bet_user in users.values(): bets_by_user = self._core.bets.LookupBets(game.name, bet_user) for _, user_bets in bets_by_user.items(): for bet in user_bets: if len(users) > 1 or users == {None: None}: bets.append( (bet.amount, '- %s, %s' % (bet.user.display_name, game.FormatBet(bet)))) else: bets.append( (bet.amount, '- %s' % game.FormatBet(bet))) bet_total += bet.amount bets.sort(key=lambda bet: bet[0], reverse=True) bets = [betstring for _, betstring in bets] if not bets: query_str = '%s has n' % query_name if query_name else 'N' return '%so current bets. Risk aversion is unbecoming' % query_str responses = [ '%s current bets [%s, %s]' % (query_name or 'All', inflect_lib.Plural( len(bets), 'bet'), util_lib.FormatHypecoins(bet_total)) ] if (len(bets) > self._params.num_bets and channel.visibility == channel_pb2.Channel.PUBLIC): responses.append('Only showing %d bets, addiction is no joke.' % self._params.num_bets) bets = bets[:self._params.num_bets] responses.extend(bets) return responses
def FormatBet(self, bet): return inflect_lib.Plural(bet.amount, '%s ticket' % self.name)
def SettleBets(self, pool, msg_fn, *args, **kwargs): # Get quotes for each symbol that has a bet quote_set = { b.target for user_bets in pool.values() for b in user_bets } quotes = self._stocks.Quotes(list(quote_set)) logging.info('Starting stock gamble, quotes: %s pool: %s', quotes, pool) pool_value = sum(x.amount for user_bets in pool.values() for x in user_bets) msg_fn( None, 'The trading day is closed! %s bet %s on stock' % (inflect_lib.Plural(len(pool), 'pleb'), util_lib.FormatHypecoins(pool_value))) winners = defaultdict(int) for user, users_bets in pool.items(): winning_symbols = [] losing_symbols = [] net_amount = 0 for bet in users_bets: stock_data = bet_pb2.StockData() bet.data.Unpack(stock_data) symbol = bet.target if not quotes.get(symbol): # No quote, take the money and whistle innocently. logging.info('Didn\'t get a quote for %s, ledger: %s', symbol, bet) continue cur_price = quotes[symbol].price prev_price = stock_data.quote bet_sign = -1 if bet.direction == bet_pb2.Bet.AGAINST else 1 price_delta = cur_price - prev_price if bet_sign * price_delta > 0: bet_result = 'Won' # User won, default to 1:1 odds winnings = bet.amount * 2 winning_symbols.append(symbol) net_amount += bet.amount winners[user] += winnings else: bet_result = 'Lost' losing_symbols.append(symbol) net_amount -= bet.amount if bet_result == 'Won': payout_str = ', payout %s' % util_lib.FormatHypecoins( winnings) else: payout_str = '' msg_fn( user, u'bet {bet[amount]} {bet[direction]} {bet[target]} at {price[prev]}' u', now at {price[cur]} => {0}{1}'.format( bet_result, payout_str, bet={ 'amount': util_lib.FormatHypecoins(bet.amount), 'direction': bet_pb2.Bet.Direction.Name(bet.direction).lower(), 'target': bet.target, }, price={ 'cur': cur_price, 'prev': prev_price })) logging.info(u'GambleStock: %s %s %s at %s, now at %s => %s%s', user, bet.direction, symbol, prev_price, cur_price, bet_result, payout_str) right_snippet = _BuildSymbolSnippet(winning_symbols, 'right') wrong_snippet = _BuildSymbolSnippet(losing_symbols, 'wrong') if net_amount == 0: summary_snippet = 'breaking even for the day' else: summary_snippet = 'ending the day %s %s' % ( 'up' if net_amount > 0 else 'down', util_lib.FormatHypecoins(abs(net_amount))) user_message = '%s was %s%s%s' % (user, right_snippet, wrong_snippet, summary_snippet) if user in winners: msg_fn(user, ('You\'ve won %s thanks to your ability to predict the ' 'whims of hedge fund managers!') % util_lib.FormatHypecoins(winners[user])) msg_fn(None, user_message) return (winners.items(), {})
def _Handle(self, channel, user, region, subcommand, order): if region: region = region.upper() region_msg = 'in %s' % region else: region = 'all' region_msg = 'across all LCS regions' subcommand = subcommand.lower() if subcommand == 'unique': num_unique, num_games = self._core.esports.GetUniqueChampCount( region) if num_games == 0: return 'I don\'t have any data =(.' avg_unique_per_game = num_games / num_unique return ('There have been {} unique champs [1 every {:.1f} ' 'games] picked or banned {}.').format( num_unique, avg_unique_per_game, region_msg) elif subcommand in ('all', 'bans', 'picks', 'wins'): specifier_to_sort_key_fn = { 'all': lambda stats: stats['picks'] + stats['bans'], 'bans': lambda stats: stats['bans'], 'picks': lambda stats: stats['picks'], 'wins': lambda stats: stats['wins'] / stats['picks'], } sort_key_fn = specifier_to_sort_key_fn[subcommand] descending = order != '^' order_str = 'Top' if descending else 'Bottom' rate_str = subcommand[:-1].title() if subcommand == 'all': rate_str = 'Pick+Ban' num_games, top_champs = self._core.esports.GetTopPickBanChamps( region, sort_key_fn, descending) min_game_str = inflect_lib.Plural(max(1, num_games / 20), 'game') responses = [ '%s Champs by %s Rate %s [min %s].' % (order_str, rate_str, region_msg, min_game_str) ] max_champ_len = max(len(x[0]) for x in top_champs) champ_str = ( '{champ:%s} - {appear_str}{rate:4.3g}%% {rate_str} rate ' '({stat_str}{win_loss_str})' % max_champ_len) for champ, stats in top_champs: responses.append( self._PopulatePickBanChampStr(champ_str, champ, stats, subcommand, num_games)) return responses canonical_name, pb_data = self._core.esports.GetChampPickBanRate( region, subcommand) if not canonical_name: return ( 'While you may want {0} to be a real champ, your team doesn\'t ' 'think {0} is a real champ.').format(subcommand) if pb_data['num_games'] == 0 or ('picks' not in pb_data and 'bans' not in pb_data): return '%s is not very popular %s.' % (canonical_name, region_msg) appear_rate = (pb_data['bans'] + pb_data['picks']) / pb_data['num_games'] win_msg = ' with a {:.0%} win rate' if pb_data['picks'] == 0: win_msg = '' else: win_msg = win_msg.format(pb_data['wins'] / pb_data['picks']) losses = pb_data['picks'] - pb_data['wins'] return '{} has appeared in {:.1%} of games ({}, {}){} ({}-{}) {}.'.format( canonical_name, appear_rate, inflect_lib.Plural(pb_data['bans'], 'ban'), inflect_lib.Plural(pb_data['picks'], 'pick'), win_msg, pb_data['wins'], losses, region_msg)
def _Handle(self, channel, unused_user, account): num_users, coins_in_circulation = self._core.bank.GetBankStats( plebs_only=True, account=account) return ('There is %s circulating among %s.' % ( util_lib.FormatHypecoins(coins_in_circulation), inflect_lib.Plural(num_users, 'pleb')))