示例#1
0
 def __init__(self, person: ps.Person, cards: List[Card],
              only_played_cards: List[Card]) -> None:
     super().__init__()
     self.person = person
     self.people = [person]
     self.decks = person.decks
     self.hide_person = True
     self.cards = cards
     self.only_played_cards = only_played_cards
     self.has_only_played_cards = len(self.only_played_cards) > 0
     for record in person.head_to_head:
         record.show_record = True
         record.opp_url = url_for('person',
                                  person_id=record.opp_mtgo_username)
     self.show_head_to_head = len(person.head_to_head) > 0
     self.tournament_organizer = self.person.name in [
         host for series in tournaments.all_series_info()
         for host in series['hosts']
     ]
     self.show_seasons = True
     achievements_text = [('tournament_wins', 'Win', 'Wins'),
                          ('tournament_entries', 'Entry', 'Entries'),
                          ('perfect_runs', 'Perfect Run', 'Perfect Runs'),
                          ('league_entries', 'Entry', 'Entries'),
                          ('perfect_run_crushes', 'Crush', 'Crushes')]
     achievements = person.get('achievements', {})
     for k, v1, vp in achievements_text:
         if k in achievements:
             setattr(
                 self, f'{k}_text',
                 ngettext(f'1 {v1}', f'%(num)d {vp}',
                          person.achievements[k]))
     self.achievements_url = url_for('achievements')
示例#2
0
 def setup_tournaments(self) -> None:
     info = tournaments.next_tournament_info()
     self.next_tournament_name = info['next_tournament_name']
     self.next_tournament_time = info['next_tournament_time']
     self.tournaments = sorted(tournaments.all_series_info(),
                               key=lambda t: t.time)
     leagues = competition.load_competitions(
         "c.competition_series_id IN (SELECT id FROM competition_series WHERE name = 'League') AND c.end_date > UNIX_TIMESTAMP(NOW())"
     )
     end_date, prev_month, shown_end = None, None, False
     for t in self.tournaments:
         month = t.time.strftime('%b')
         if month != prev_month:
             t.month = month
             prev_month = month
         t.date = t.time.day
         if leagues and t.time >= leagues[
                 -1].start_date and t.time < leagues[-1].end_date:
             t.league = leagues.pop(-1)
             t.league.display = True
             end_date = t.league.end_date
         elif not shown_end and end_date and t.time >= end_date:
             t.league = {'class': 'begin', 'display': False}
             shown_end = True
         elif end_date:
             t.league = {'class': 'ongoing', 'display': False}
示例#3
0
 def __init__(self, src):
     if src == 'gp':
         self.show_gp_card = True
         self.gp_card_url = url_for('static', filename='images/gp_card.png')
     self.cards = exciting_cards()
     self.num_tournaments = inflect.engine().number_to_words(
         len(tournaments.all_series_info())).title()
    def __init__(self):

        info = tournaments.next_tournament_info()
        self.next_tournament_name = info['next_tournament_name']
        self.next_tournament_time = info['next_tournament_time']
        self.leaderboards_url = url_for('tournament_leaderboards')

        self.tournaments = sorted(tournaments.all_series_info(),
                                  key=lambda t: t.time)
        leagues = competition.load_competitions(
            "c.competition_series_id IN (SELECT id FROM competition_series WHERE name = 'League') AND c.end_date > UNIX_TIMESTAMP(NOW())"
        )
        end_date, prev_month, shown_end = None, None, False
        for t in self.tournaments:
            month = t.time.strftime('%b')
            if month != prev_month:
                t.month = month
                prev_month = month
            t.date = t.time.day
            if len(leagues) > 0 and t.time >= leagues[
                    -1].start_date and t.time < leagues[-1].end_date:
                t.league = leagues.pop(-1)
                t.league.display = True
                end_date = t.league.end_date
            elif not shown_end and end_date and t.time >= end_date:
                t.league = {'class': 'begin', 'display': False}
                shown_end = True
            elif end_date:
                t.league = {'class': 'ongoing', 'display': False}
        self.num_tournaments = inflect.engine().number_to_words(
            len(self.tournaments))
        self.bugs_url = url_for('bugs')
        self.prizes = tournaments.prizes_by_finish()
示例#5
0
 def __init__(self) -> None:
     super().__init__()
     hosts = [
         host for series in tournaments.all_series_info()
         for host in series['hosts']
     ]
     hosts += ['stash86']
     self.hosts = ', '.join(set(hosts))
 def __init__(self, person):
     self.person = person
     self.decks = person.decks
     self.hide_person = True
     self.cards = card.played_cards(
         'd.person_id = {person_id}'.format(person_id=sqlescape(person.id)))
     self.only_played_cards = card.only_played_by(person.id)
     self.has_only_played_cards = len(self.only_played_cards) > 0
     for record in person.head_to_head:
         record.show_record = True
         record.opp_url = url_for('person',
                                  person_id=record.opp_mtgo_username)
     self.show_head_to_head = len(person.head_to_head) > 0
     self.tournament_organizer = self.person.name in [
         host for series in tournaments.all_series_info()
         for host in series['hosts']
     ]
示例#7
0
 def __init__(self, person, cards, only_played_cards) -> None:
     super().__init__()
     self.person = person
     self.decks = person.decks
     self.hide_person = True
     self.cards = cards
     self.only_played_cards = only_played_cards
     self.has_only_played_cards = len(self.only_played_cards) > 0
     for record in person.head_to_head:
         record.show_record = True
         record.opp_url = url_for('person',
                                  person_id=record.opp_mtgo_username)
     self.show_head_to_head = len(person.head_to_head) > 0
     self.tournament_organizer = self.person.name in [
         host for series in tournaments.all_series_info()
         for host in series['hosts']
     ]
     self.show_seasons = True
示例#8
0
 def num_tournaments(self) -> str:
     return inflect.engine().number_to_words(
         len(tournaments.all_series_info()))
 def __init__(self) -> None:
     self.hosts = [
         host for series in tournaments.all_series_info()
         for host in series['hosts']
     ]
示例#10
0
    async def explain(self, client: Client, channel: Channel, args: str,
                      **_: Dict[str, Any]) -> None:
        """`!explain`. Get a list of things the bot knows how to explain.
`!explain {thing}`. Print commonly needed explanation for 'thing'."""
        num_tournaments = inflect.engine().number_to_words(
            len(tournaments.all_series_info()))
        explanations: Dict[str, Tuple[str, Dict[str, str]]] = {
            'bugs':
            ('We keep track of cards that are bugged on Magic Online. We allow the playing of cards with known bugs in Penny Dreadful under certain conditions. See the full rules on the website.',
             {
                 'Known Bugs List':
                 fetcher.decksite_url('/bugs/'),
                 'Tournament Rules':
                 fetcher.decksite_url('/tournaments/#bugs'),
                 'Bugged Cards Database':
                 'https://github.com/PennyDreadfulMTG/modo-bugs/issues/'
             }),
            'deckbuilding': ("""
                The best way to build decks is to use a search engine that supports Penny Dreadful legality (`f:pd`) like Scryfall.
                You can find Penny Dreadful decklists from tournaments, leagues and elsewhere at pennydreadfulmagic.com.
                """, {
                'Scryfall':
                'https://scryfall.com/',
                'Latest Decks':
                fetcher.decksite_url('/'),
                'Legal Cards List':
                'http://pdmtgo.com/legal_cards.txt'
            }),
            'decklists': ("""
                You can find Penny Dreadful decklists from tournaments, leagues and elsewhere at pennydreadfulmagic.com
                """, {
                'Latest Decks': fetcher.decksite_url('/')
            }),
            'doorprize':
            ("The door prize is 1 tik credit with Cardhoarder, awarded to one randomly-selected player that completes the Swiss rounds but doesn't make top 8.",
             {}),
            'league': ("""
                Leagues last for roughly a month. You may enter any number of times but only one deck at a time.
                You play five matches per run. You can join the league at any time.
                To find a game sign up and then create a game in Just for Fun with "Penny Dreadful League" as the comment.
                Top 8 finishers on each month's league leaderboard win credit with MTGO Traders.
                When you complete a five match league run for the first time ever you will get 1 tik credit with MTGO Traders.
                """, {
                'More Info':
                fetcher.decksite_url('/league/'),
                'Sign Up':
                fetcher.decksite_url('/signup/'),
                'Current League':
                fetcher.decksite_url('/league/current/')
            }),
            'legality': ("""
                Legality is determined at the release of a Standard-legal set on Magic Online.
                Prices are checked every hour for a week. Anything 1c or less for half or more of all checks is legal for the season.
                Cards from the just-released set are added (nothing removed) a couple of weeks later via a supplemental rotation after prices have settled a little.
                Any version of a card on the legal cards list is legal.
                """, {
                'Deck Checker':
                'http://pdmtgo.com/deck_check.html',
                'Legal Cards List':
                'http://pdmtgo.com/legal_cards.txt',
                'Rotation Speculation':
                fetcher.decksite_url('/rotation/speculation/'),
                'Rotation Changes':
                fetcher.decksite_url('/rotation/changes/')
            }),
            'noshow': ("""
                If your opponent does not join your game please @-message them on Discord and contact them on Magic Online.
                If you haven't heard from them by 10 minutes after the start of the round let the Tournament Organizer know.
                You will receive a 2-0 win and your opponent will be dropped from the competition.
                """, {}),
            'playing': ("""
                To get a match go to Constructed Open Play, Just for Fun on MTGO and create a Freeform game with "Penny Dreadful" in the comments.
                """, {}),
            'prices': ("""
                The price output contains current price.
                If the price is low enough it will show season-low and season-high also.
                If the card has been 1c at any point this season it will also include the amount of time (as a percentage) the card has spent at 1c or below this week, month and season.
                """, {}),
            'prizes': ("""
                Gatherling tournaments pay prizes to the Top 8 in Cardhoarder credit.
                This credit will appear when you trade with one of their bots on Magic Online.
                One player not making Top 8 but playing all the Swiss rounds will be randomly allocated the door prize.
                Prizes are credited once a week usually on the Friday or Saturday following the tournament but may sometimes take longer.
                """, {
                'More Info': fetcher.decksite_url('/tournaments/')
            }),
            'report': ("""
                For gatherling.com tournaments PDBot is information-only, *both* players must report near the top of Player CP.
                If PDBot reports your league match in Discord you don't need to do anything (only league matches, tournament matches must still be reported). If not, either player can report.
                """, {
                'Gatherling': 'https://gatherling.com/player.php',
                'League Report': fetcher.decksite_url('/report/')
            }),
            'retire':
            ('To retire from a league run message PDBot on MTGO with `!retire`. If you have authenticated with Discord on pennydreadfulmagic.com you can say `!retire` on Discord or retire on the website.',
             {
                 'Retire': fetcher.decksite_url('/retire/')
             }),
            'tournament': ("""
                We have {num_tournaments} free-to-enter weekly tournaments, most of which have prizes from Cardhoarder.
                They are hosted on gatherling.com along with a lot of other player-run Magic Online events.
                """.format(num_tournaments=num_tournaments), {
                'More Info': fetcher.decksite_url('/tournaments/'),
                'Sign Up': 'https://gatherling.com/',
            }),
            'username': ("""
                Please change your Discord username to include your MTGO username so we can know who you are.
                To change, right-click your username.
                This will not affect any other Discord channel.
                """, {})
        }
        keys = sorted(explanations.keys())
        explanations['drop'] = explanations['retire']
        explanations['rotation'] = explanations['legality']
        explanations['tournaments'] = explanations['tournament']
        word = args.strip().lower().rstrip(
            's'
        )  # strip trailing 's' to make 'leagues' match 'league' and simliar without affecting the output of `!explain` to be unnecessarily plural.
        if len(word) > 0:
            for k in explanations:
                if k.startswith(word):
                    word = k
        try:
            s = '{text}\n'.format(text=textwrap.dedent(explanations[word][0]))
        except KeyError:
            usage = 'I can explain any of these things: {things}'.format(
                things=', '.join(sorted(keys)))
            return await client.send_message(channel, usage)
        for k in sorted(explanations[word][1].keys()):
            s += '{k}: <{v}>\n'.format(k=k, v=explanations[word][1][k])
        await client.send_message(channel, s)
示例#11
0
async def explain(ctx: MtgContext, *, thing: Optional[str]) -> None:
    """Answers for Frequently Asked Questions
`!explain`. Get a list of things the bot knows how to explain.
`!explain {thing}`. Print commonly needed explanation for 'thing'."""
    num_tournaments = inflect.engine().number_to_words(
        len(tournaments.all_series_info()))
    explanations: Dict[str, Tuple[str, Dict[str, str]]] = {
        'archetype': ("""
            Archetypes are manually reviewed by a human on an irregular basis.
            Prior to that a deck will have either its assigned archetype on Gatherling (tournament decks), nothing, or a best-guess based on the most similar reviewed deck (league decks).
            If you want to help out let us know.
            """, {}),
        'bugs':
        ('We keep track of cards that are bugged on Magic Online. We allow the playing of cards with known bugs in Penny Dreadful under certain conditions. See the full rules on the website.',
         {
             'Known Bugs List':
             fetcher.decksite_url('/bugs/'),
             'Tournament Rules':
             fetcher.decksite_url('/tournaments/#bugs'),
             'Bugged Cards Database':
             'https://github.com/PennyDreadfulMTG/modo-bugs/issues/'
         }),
        'deckbuilding': ("""
            The best way to build decks is to use a search engine that supports Penny Dreadful legality (`f:pd`) like Scryfall.
            You can find Penny Dreadful decklists from tournaments, leagues and elsewhere at pennydreadfulmagic.com.
            """, {
            'Scryfall':
            'https://scryfall.com/',
            'Latest Decks':
            fetcher.decksite_url('/'),
            'Legal Cards List':
            'http://pdmtgo.com/legal_cards.txt'
        }),
        'decklists': ("""
            You can find Penny Dreadful decklists from tournaments, leagues and elsewhere at pennydreadfulmagic.com
            """, {
            'Latest Decks': fetcher.decksite_url('/')
        }),
        'doorprize':
        ("The door prize is 1 tik credit with Cardhoarder, awarded to one randomly-selected player that completes the Swiss rounds but doesn't make top 8.",
         {}),
        'language': ("""
            To change the language you see the site in use the language switcher in the top-left hand corner (desktop only) or follow the link below for English.
            """, {
            'PDM in English': fetcher.decksite_url('/?locale=en')
        }),
        'league': ("""
            Leagues last for roughly a month. You may enter any number of times but only one deck at a time.
            You play five matches per run. You can join the league at any time.
            To find a game sign up and then create a game in Constructed, Specialty, Freeform Tournament Practice with "Penny Dreadful League" as the comment.
            Top 8 finishers on each month's league leaderboard win credit with MTGO Traders.
            When you complete a five match league run for the first time ever you will get 1 tik credit with MTGO Traders (at the end of the month).
            """, {
            'More Info': fetcher.decksite_url('/league/'),
            'Sign Up': fetcher.decksite_url('/signup/'),
            'Current League': fetcher.decksite_url('/league/current/')
        }),
        'netdecking': ("""
            Netdecking is not only allowed, it is encouraged! Most deck creators are happy when others play their decks!
            You can find the best tournament winning decks in the link below. Sort by records to find the best tournament winning decks!
            """, {
            'Decklists': fetcher.decksite_url('/decks/'),
        }),
        'noshow': ("""
            If your opponent does not join your game please @-message them on Discord and contact them on Magic Online.
            If you haven't heard from them by 10 minutes after the start of the round let the Tournament Organizer know.
            You will receive a 2-0 win and your opponent will be dropped from the competition.
            """, {}),
        'onegame': ("""
            If your opponent concedes or times out before the match completes, PDBot will not report automatically.
            If you feel enough of a match was played you may manually report 2-x where x is the number of games your opponent won.
            """, {
            'Report': fetcher.decksite_url('/report/')
        }),
        'playing': ("""
            To get a match go to Constructed, Specialty, Freeform Tournament Practice on MTGO and create a match with "Penny Dreadful" in the comments.
            """, {}),
        'prices': (f"""
            The price output contains current price.
            If the price is low enough it will show season-low and season-high also.
            If the card has been {card_price.MAX_PRICE_TEXT} or less at any point this season it will also include the amount of time (as a percentage) the card has spent at {card_price.MAX_PRICE_TEXT} or below this week, month and season.
            """, {}),
        'prizes': ("""
            Gatherling tournaments pay prizes to the Top 8 in Cardhoarder credit.
            This credit will appear when you trade with one of their bots on Magic Online.
            One player not making Top 8 but playing all the Swiss rounds will be randomly allocated the door prize.
            Prizes are credited once a week usually on the Friday or Saturday following the tournament but may sometimes take longer.
            """, {
            'More Info': fetcher.decksite_url('/tournaments/')
        }),
        'replay': ("""
            You can play the same person a second time on your league run as long as they have started a new run. The same two runs cannot play each other twice.
            """, {}),
        'reporting': ("""
            """, {}),
        'retire':
        ('To retire from a league run message PDBot on MTGO with `!retire`. If you have authenticated with Discord on pennydreadfulmagic.com you can say `!retire` on Discord or retire on the website.',
         {
             'Retire': fetcher.decksite_url('/retire/')
         }),
        'rotation': (f"""
            Legality is set a week after the release of a Standard-legal set on Magic Online.
            Prices are checked every hour for a week from the set release. Anything {card_price.MAX_PRICE_TEXT} or less for half or more of all checks is legal for the season.
            Any version of a card on the legal cards list is legal.
            """, {}),
        'spectating': ("""
            Spectating tournament and league matches is allowed and encouraged.
            Please do not write anything in chat except to call PDBot's `!record` command to find out the current score in games.
            """, {}),
        'tournament': ("""
            We have {num_tournaments} free-to-enter weekly tournaments that award trade credit prizes from Cardhoarder.
            They are hosted on gatherling.com along with a lot of other player-run Magic Online events.
            """.format(num_tournaments=num_tournaments), {
            'More Info': fetcher.decksite_url('/tournaments/'),
            'Sign Up': 'https://gatherling.com/',
        }),
        'username': ("""
            Please change your Discord username to include your MTGO username so we can know who you are.
            To change, right-click your username.
            This will not affect any other Discord channel.
            """, {}),
        'verification': ("""
            Gatherling verification is currently broken.
            It no longer does anything except put a green tick by your name anyway.
            """, {}),
    }
    reporting_explanations: Dict[str, Tuple[str, Dict[str, str]]] = {
        'tournament': ("""
            For tournaments PDBot is information-only, *both* players must report near the top of Player CP (or follow the link at the top of any Gatherling page).
            """, {
            'Gatherling': 'https://gatherling.com/player.php',
        }),
        'league': ("""
            If PDBot reports your league match in #league in Discord you don't need to do anything. If not, either player can report.
            """, {
            'League Report': fetcher.decksite_url('/report/')
        })
    }
    keys = sorted(explanations.keys())
    explanations['drop'] = explanations['retire']
    explanations['legality'] = explanations['rotation']
    explanations['spectate'] = explanations['spectating']
    explanations['tournaments'] = explanations['tournament']
    explanations['watching'] = explanations['spectating']
    explanations['spectate'] = explanations['spectating']
    explanations['verify'] = explanations['verification']
    # strip trailing 's' to make 'leagues' match 'league' and simliar without affecting the output of `!explain` to be unnecessarily plural.
    if thing is None:
        thing = ''
    word = thing.lower().replace(' ', '').rstrip('s')
    if len(word) > 0:
        for k in explanations:
            if k.startswith(word):
                word = k
    try:
        if word == 'reporting':
            if is_tournament_channel(ctx.channel):
                explanation = reporting_explanations['tournament']
            else:
                explanation = reporting_explanations['league']
        else:
            explanation = explanations[word]

        s = '{text}\n'.format(text=textwrap.dedent(explanation[0]))
    except KeyError:
        usage = 'I can explain any of these things: {things}'.format(
            things=', '.join(sorted(keys)))
        await ctx.send(usage)
        return
    for k in sorted(explanation[1].keys()):
        s += '{k}: <{v}>\n'.format(k=k, v=explanation[1][k])
    await ctx.send(s)
 def __init__(self):
     hosts = [host for series in tournaments.all_series_info() for host in series['hosts']]
     hosts += ['chaosblackdoom', 'hexalite']
     self.hosts = ', '.join(set(hosts))
示例#13
0
def all_tournaments() -> Response:
    data = {}
    data['tournaments'] = (tournaments.all_series_info())
    return return_json(data)