Example #1
0
 async def deck(self, ctx: commands.Context, *,
                nation: Union[int, Link[Nation]]):
     """Retrieves general info about the specified nation's deck."""
     is_id = isinstance(nation, int)
     if is_id:
         api = Api("cards info", nationid=nation)
     else:
         api = Api("cards info", nationname=nation)
     root = await api
     if not root.INFO.countchildren():
         if is_id:
             return await ctx.send(f"No such deck for ID {nation}.")
         return await ctx.send(f"No such deck for nation {nation!r}.")
     n_id = root.INFO.NAME.text
     if n_id not in self.db_cache:
         self.db_cache[n_id] = {"dbid": root.INFO.ID.pyval}
         await self.config.custom("NATION",
                                  n_id).dbid.set(root.INFO.ID.pyval)
     embed = ProxyEmbed(
         title=n_id.replace("_", " ").title(),
         url=f"https://www.nationstates.net/page=deck/nation={n_id}",
         description=f"{root.INFO.NUM_CARDS.text} cards",
         colour=await ctx.embed_colour(),
         timestamp=datetime.utcfromtimestamp(root.INFO.LAST_VALUED.pyval),
     )
     embed.add_field(name="Bank", value=root.INFO.BANK.text)
     embed.add_field(
         name="Deck Value",
         value=
         f"[{root.INFO.DECK_VALUE.text}](https://www.nationstates.net/nation={n_id}/detail=trend/censusid=86)"
         f"\nRanked #{root.INFO.RANK.text} worldwide, #{root.INFO.REGION_RANK.text} regionally.",
         inline=False,
     )
     embed.set_footer(text="Last Valued")
     await embed.send_to(ctx)
Example #2
0
    async def invoice(self, ctx):
        """
        Configure or view settings for automated voice-based permissions.
        """
        if ctx.invoked_subcommand:
            return
        color = await ctx.embed_colour()

        embed = ProxyEmbed(title=f"Current settings", color=color)
        g_settings = self.guild_cache[ctx.guild.id]
        g_msg = []
        for key, value in g_settings.items():
            if value is not None and key == "role":
                value = ctx.guild.get_role(value)
                value = value.name if value else "<Deleted role>"
            key = key.replace("_", " ").title()
            g_msg.append(f"{key}: {value}")
        embed.add_field(name=f"Guild {ctx.guild} settings", value="\n".join(g_msg))

        vc = ctx.author.voice.channel if ctx.author.voice else None
        if vc:
            c_settings = self.channel_cache[ctx.channel.id]
            c_msg = []
            for key, value in c_settings.items():
                if value is not None:
                    if key == "role":
                        value = ctx.guild.get_role(value)
                        value = value.name if value else "<Deleted role>"
                    elif key == "channel":
                        value = ctx.guild.get_channel(value)
                        value = value.name if value else "<Deleted channel>"
                key = key.replace("_", " ").title()
                c_msg.append(f"{key}: {value}")
            embed.add_field(name=f"Channel {vc} settings", value="\n".join(c_msg))
        await embed.send_to(ctx)
Example #3
0
    async def show(
        self,
        ctx: commands.GuildContext,
        *,
        scope: Union[discord.CategoryChannel, GuildVoice] = None,
    ):
        """
        Show the current settings for the specified scope.

        See `[p]help invoice set` for explanations of the various settings.
        """
        guild = ctx.guild
        scoped = scope or guild
        chain = Chain.from_scope(scoped, self.cache)
        embed = ProxyEmbed(title=f"Current settings for {scoped}",
                           color=await ctx.embed_color())
        for key, value in chain.items():
            if value and key == "role":
                value = guild.get_role(value) or "<Deleted role>"
            elif value and key == "channel":
                value = guild.get_channel(value) or "<Deleted channel>"
            elif not value and key == "dynamic_name":
                value = "\N{SPEAKER WITH THREE SOUND WAVES} {vc}"
            else:
                value = value or False
            embed.add_field(name=key.replace("_", " ").title(),
                            value=getattr(value, "mention", str(value)))
        embed.set_footer(
            text=
            "Settings shown here reflect the effective settings for the scope,"
            " including inherited settings from the category or guild.")
        await embed.send_to(
            ctx, allowed_mentions=discord.AllowedMentions(users=False))
Example #4
0
    async def wa(self,
                 ctx: commands.Context,
                 resolution_id: Optional[int] = None,
                 *options: WA):
        """
        Retrieves general info about World Assembly resolutions.

        Defaults to the General Assembly. Use [p]sc to get info about the Security Council.
        If no resolution ID is provided, the current at-vote resolution is used.
        Valid options:
            text - The resolution's text
            votes - The total votes for and against
            nations - The total nations for and against
            delegates - The top ten Delegates for and against
        """
        option = WA.collapse(*options, default=0)
        if resolution_id and option & (WA.NATION | WA.DELEGATE):
            return await ctx.send(
                "The Nations and Delegates options are not available for past resolutions."
            )
        is_sc = ctx.invoked_with == "sc"
        shards = ["resolution"]
        request = {"wa": "2" if is_sc else "1"}
        if option & WA.DELEGATE:
            shards.append("delvotes")
        if resolution_id:
            request["id"] = str(resolution_id)
        else:
            shards.append("lastresolution")
        root = await Api(request, q=shards)
        if not root.RESOLUTION.countchildren():
            out = (unescape(root.LASTRESOLUTION.text).replace(
                "<strong>", "**").replace("</strong>", "**"))
            try:
                out = "{}[{}](https://www.nationstates.net{}){}".format(
                    out[:out.index("<a")],
                    out[out.index('">') + 2:out.index("</a")],
                    out[out.index('="') + 2:out.index('">')],
                    out[out.index("</a>") + 4:],
                )
            except ValueError:
                pass
            embed = ProxyEmbed(title="Last Resolution",
                               description=out,
                               colour=await ctx.embed_colour())
            embed.set_thumbnail(
                url="https://www.nationstates.net/images/{}.jpg".format(
                    "sc" if is_sc else "ga"))
            return await embed.send_to(ctx)
        root = root.RESOLUTION
        img = {
            "Commendation": "images/commend.png",
            "Condemnation": "images/condemn.png",
            "Liberation": "images/liberate.png",
        }.get(root.CATEGORY.text, "images/ga.jpg")
        if option & WA.TEXT:
            description = "**Category: {}**\n\n{}".format(
                root.CATEGORY.text, escape(root.DESC.text, formatting=True))
            short = next(
                pagify(
                    description,
                    delims=("\n", " ", "]"),
                    escape_mass_mentions=False,
                    page_length=2047,
                    priority=True,
                ))
            if len(short) < len(description):
                description = short + "\N{HORIZONTAL ELLIPSIS}"
        else:
            description = "Category: {}".format(root.CATEGORY.text)
        if resolution_id:
            impl = root.IMPLEMENTED.pyval
        else:
            # mobile embeds can't handle the FUTURE
            impl = root.PROMOTED.pyval  # + (4 * 24 * 60 * 60)  # 4 Days
        embed = ProxyEmbed(
            title=root.NAME.text,
            url="https://www.nationstates.net/page={}".format(
                "sc" if is_sc else "ga") if not resolution_id else
            "https://www.nationstates.net/page=WA_past_resolution/id={}/council={}"
            .format(resolution_id, "2" if is_sc else "1"),
            description=description,
            timestamp=datetime.utcfromtimestamp(impl),
            colour=await ctx.embed_colour(),
        )
        try:
            authroot = await Api("fullname flag", nation=root.PROPOSED_BY.text)
        except NotFound:
            embed.set_author(
                name=root.PROPOSED_BY.text.replace("_", " ").title(),
                url="https://www.nationstates.net/page=boneyard?nation={}".
                format(root.PROPOSED_BY.text),
                icon_url="http://i.imgur.com/Pp1zO19.png",
            )
        else:
            embed.set_author(
                name=authroot.FULLNAME.text,
                url="https://www.nationstates.net/nation={}".format(
                    root.PROPOSED_BY.text),
                icon_url=authroot.FLAG.text,
            )
        embed.set_thumbnail(url="https://www.nationstates.net/{}".format(img))
        if option & WA.DELEGATE:
            for_del_votes = heapq.nlargest(
                10,
                root.iterfind("DELVOTES_FOR/DELEGATE"),
                key=operator.attrgetter("VOTES.pyval"))
            against_del_votes = heapq.nlargest(
                10,
                root.iterfind("DELVOTES_AGAINST/DELEGATE"),
                key=operator.attrgetter("VOTES.pyval"),
            )
            if for_del_votes:
                embed.add_field(
                    name="Top Delegates For",
                    value="\t|\t".join(
                        "[{}](https://www.nationstates.net/nation={}) ({})".
                        format(
                            e.NATION.text.replace("_", " ").title(),
                            e.NATION.text, e.VOTES.text)
                        for e in for_del_votes),
                    inline=False,
                )
            if against_del_votes:
                embed.add_field(
                    name="Top Delegates Against",
                    value="\t|\t".join(
                        "[{}](https://www.nationstates.net/nation={}) ({})".
                        format(
                            e.NATION.text.replace("_", " ").title(),
                            e.NATION.text, e.VOTES.text)
                        for e in against_del_votes),
                    inline=False,
                )
        if option & WA.VOTE:
            percent = (
                100 * root.TOTAL_VOTES_FOR.pyval /
                (root.TOTAL_VOTES_FOR.pyval + root.TOTAL_VOTES_AGAINST.pyval))
            embed.add_field(
                name="Total Votes",
                value="For {}\t{:◄<13}\t{} Against".format(
                    root.TOTAL_VOTES_FOR.pyval,
                    "►" * int(round(percent / 10)) + str(int(round(percent))) +
                    "%",
                    root.TOTAL_VOTES_AGAINST.pyval,
                ),
                inline=False,
            )
        if option & WA.NATION:
            percent = (100 * root.TOTAL_NATIONS_FOR.pyval /
                       (root.TOTAL_NATIONS_FOR.pyval +
                        root.TOTAL_NATIONS_AGAINST.pyval))
            embed.add_field(
                name="Total Nations",
                value="For {}\t{:◄<13}\t{} Against".format(
                    root.TOTAL_NATIONS_FOR.pyval,
                    "►" * int(round(percent / 10)) + str(int(round(percent))) +
                    "%",
                    root.TOTAL_NATIONS_AGAINST.pyval,
                ),
                inline=False,
            )
        # I can only blame my own buggy code for the following
        repealed_by = root.find("REPEALED_BY")
        if repealed_by is not None:
            embed.add_field(
                name="Repealed By",
                value=
                '[Repeal "{}"](https://www.nationstates.net/page=WA_past_resolution/id={}/council={})'
                .format(root.NAME.text, root.REPEALED_BY.text,
                        "2" if is_sc else "1"),
                inline=False,
            )
        repeals = root.find("REPEALS_COUNCILID")
        if repeals is not None:
            embed.add_field(
                name="Repeals",
                value=
                "[{}](https://www.nationstates.net/page=WA_past_resolution/id={}/council={})"
                .format(root.NAME.text[8:-1], repeals, "2" if is_sc else "1"),
                inline=False,
            )
        embed.set_footer(text="Passed" if resolution_id else "Voting Started")
        await embed.send_to(ctx)
Example #5
0
    async def card(
        self,
        ctx: commands.Context,
        season: Optional[int] = 2,
        *,
        nation: Optional[Union[int, Link[Nation]]] = None,
    ):
        """
        Retrieves general info about the specified card.

        If a number is provided, the bot will look for the card with that ID.
        Otherwise, the bot will look for the specified nation's card.

        If you want to find a nation that has a numerical name,
        use a link or "quotes" to specify that it is a name, and not an ID.
        A season must be specified if this is the case.
        """
        if season is not None and nation is None:
            season, nation = 2, season
        if isinstance(nation, str) and nation not in self.db_cache:
            api = Api("dbid", nation=nation)
            try:
                root = await api
            except NotFound:
                return await ctx.send(
                    f"Nation {nation!r} does not exist. "
                    "Please provide its card ID instead, and I'll remember it for next time."
                )
            n_id, nation = root.get("id"), root.DBID.pyval
            self.db_cache[n_id] = {"dbid": nation}
            await self.config.custom("NATION", n_id).dbid.set(nation)
        else:
            n_id, nation = None, self.db_cache.get(nation,
                                                   {}).get("dbid", nation)
        assert isinstance(nation, int), repr(nation)
        api = Api("card info markets", cardid=nation, season=season)
        root = await api
        if not root.countchildren():
            if n_id:
                return await ctx.send(
                    f"No such S{season} card for nation {n_id!r}.")
            return await ctx.send(f"No such S{season} card for ID {nation!r}.")
        n_id = root.NAME.text.casefold().replace(" ", "_")
        if n_id not in self.db_cache:
            self.db_cache[n_id] = {"dbid": nation}
            await self.config.custom("NATION", n_id).dbid.set(nation)
        embed = ProxyEmbed(
            title=f"The {root.TYPE.text} of {root.NAME.text}",
            url=
            f"https://www.nationstates.net/page=deck/card={nation}/season={season}",
            colour=CARD_COLORS.get(root.CATEGORY.text, 0),
        )
        embed.set_author(name=root.CATEGORY.text.title())
        embed.set_thumbnail(
            url=
            f"https://www.nationstates.net/images/cards/s{season}/{root.FLAG.text}"
        )
        embed.add_field(
            name="Market Value (estimated)",
            value=box(root.MARKET_VALUE.text, lang="swift"),
            inline=False,
        )
        sellers: List[Tuple[int, str]] = []
        buyers: List[Tuple[int, str]] = []
        for market in root.MARKETS.iterchildren():
            if market.TYPE.text == "bid":
                # negative price to reverse sorting
                bisect.insort(buyers,
                              (-market.PRICE.pyval,
                               market.NATION.text.replace("_", " ").title()))
            elif market.TYPE.text == "ask":
                bisect.insort(sellers,
                              (market.PRICE.pyval,
                               market.NATION.text.replace("_", " ").title()))
        if not any((buyers, sellers)):
            return await embed.send_to(ctx)
        max_listed = 5
        max_len = max(len(buyers), len(sellers))
        max_len = min(max_len, max_listed + 1)
        for is_buyers, arr in enumerate((sellers, buyers)):
            pad = "\n\u200b" * max(0, max_len - len(arr))
            if not arr:
                embed.add_field(name="Buyers" if is_buyers else "Sellers",
                                value=box(pad))
                embed.overwrites.set_field_at(
                    is_buyers + 1,
                    name=embed.fields[is_buyers + 1].name,
                    value=box("\u200b", lang="swift"),
                )
                continue
            tarr = [
                f"{-j[0]:.02f}\xa0{j[1]}"
                if is_buyers else f"{j[1]}\xa0{j[0]:.02f}"
                for j in arr[:max_listed]
            ]
            if len(arr) > max_listed:
                num = len(arr) - max_listed
                tarr.append(
                    f"+ {num} more {'bid' if is_buyers else 'ask'}{'' if num == 1 else 's'}\N{HORIZONTAL ELLIPSIS}"
                )
            raw_text = "\n".join(tarr)
            if not is_buyers:
                width = max(map(len, tarr))
                for i, t in enumerate(tarr):
                    tarr[i] = t.rjust(width)
            text = "\n".join(tarr) + pad
            embed.add_field(name="Buyers" if is_buyers else "Sellers",
                            value=box(text, lang="swift"))
            embed.overwrites.set_field_at(
                is_buyers + 1,
                name=embed.fields[is_buyers + 1].name,
                value=box(raw_text, lang="swift"),
            )
        await embed.send_to(ctx)
Example #6
0
    async def region(self, ctx: commands.Context, *, region: Link[Region]):
        """Retrieves general info about a specified NationStates region"""
        api: Api = Api(
            "delegate delegateauth delegatevotes flag founded founder founderauth lastupdate name numnations power tags zombie",
            region=region,
        )
        try:
            root = await api
        except NotFound:
            embed = ProxyEmbed(title=region.replace("_", " ").title(),
                               description="This region does not exist.")
            embed.set_author(name="NationStates",
                             url="https://www.nationstates.net/")
            return await embed.send_to(ctx)
        if root.DELEGATE.text == "0":
            delvalue = "No Delegate"
        else:
            endo = root.DELEGATEVOTES.pyval - 1
            if endo == 1:
                endo = "{:.0f} endorsement".format(endo)
            else:
                endo = "{:.0f} endorsements".format(endo)
            delvalue = "[{}](https://www.nationstates.net/nation={}) | {}".format(
                root.DELEGATE.text.replace("_", " ").title(),
                root.DELEGATE.text, endo)
        if "X" in root.DELEGATEAUTH.text:
            delheader = "Delegate"
        else:
            delheader = "Delegate (Non-Executive)"
        tags = {t.text for t in root.iterfind("TAGS/TAG")}
        founderless = "Founderless" in tags
        founded = "in Antiquity" if root.FOUNDED.pyval == 0 else root.FOUNDED.pyval
        if root.FOUNDER.text == "0":
            foundervalue = "No Founder"
        else:
            if founderless:
                url = "https://www.nationstates.net/page=boneyard?nation="
            else:
                url = "https://www.nationstates.net/nation="
            foundervalue = "[{}]({}{}){}".format(
                root.FOUNDER.text.replace("_", " ").title(),
                url,
                root.FOUNDER.text,
                " (Ceased to Exist)" if founderless else "",
            )
        founderheader = "Founderless" if founderless else "Founder"
        if not root.FOUNDERAUTH.text or "X" not in root.FOUNDERAUTH.text:
            founderheader += " (Non-Executive)"
        fash = "Fascist" in tags and "Anti-Fascist" not in tags  # why do people hoard tags...
        name = "{}{}".format("\N{LOCK} " if "Password" in tags else "",
                             root.NAME.text)
        warning = (
            "\n**```css\n\N{HEAVY EXCLAMATION MARK SYMBOL} Region Tagged as Fascist \N{HEAVY EXCLAMATION MARK SYMBOL}\n```**"
            if fash else "")

        description = "[{} nations](https://www.nationstates.net/region={}/page=list_nations) | Founded {} | Power: {}{}".format(
            root.NUMNATIONS.pyval, root.get("id"), founded, root.POWER.text,
            warning)
        is_zday = self._is_zday(ctx.message,
                                dev=ctx.author.id == 215640856839979008)
        embed = ProxyEmbed(
            title=name,
            url="https://www.nationstates.net/region={}".format(
                root.get("id")),
            description=description,
            timestamp=datetime.utcfromtimestamp(root.LASTUPDATE.pyval),
            colour=0x000001
            if fash else 0x8BBC21 if is_zday else await ctx.embed_colour(),
        )
        embed.set_author(name="NationStates",
                         url="https://www.nationstates.net/")
        if root.FLAG.text:
            embed.set_thumbnail(url=root.FLAG.text)
        embed.add_field(name=founderheader, value=foundervalue, inline=False)
        embed.add_field(name=delheader, value=delvalue, inline=False)
        if is_zday:
            embed.add_field(
                name="Zombies",
                value="Survivors: {} | Zombies: {} | Dead: {}".format(
                    self._illion(root.ZOMBIE.SURVIVORS),
                    self._illion(root.ZOMBIE.ZOMBIES),
                    self._illion(root.ZOMBIE.DEAD),
                ),
                inline=False,
            )
        embed.set_footer(text="Last Updated")
        await embed.send_to(ctx)
Example #7
0
 async def nation(self, ctx: commands.Context, *, nation: Link[Nation]):
     """Retrieves general info about a specified NationStates nation"""
     api: Api = Api(
         "census category dbid",
         "demonym2plural flag founded freedom",
         "fullname influence lastlogin motto",
         "name population region wa zombie",
         nation=nation,
         mode="score",
         scale="65 66",
     )
     try:
         root = await api
     except NotFound:
         embed = ProxyEmbed(
             title=nation.replace("_", " ").title(),
             url="https://www.nationstates.net/page="
             "boneyard?nation={}".format(nation),
             description="This nation does not exist.",
         )
         embed.set_author(name="NationStates",
                          url="https://www.nationstates.net/")
         embed.set_thumbnail(url="http://i.imgur.com/Pp1zO19.png")
         return await embed.send_to(ctx)
     n_id = root.get("id")
     if n_id not in self.db_cache:
         self.db_cache[n_id] = {"dbid": root.DBID.pyval}
         await self.config.custom("NATION", n_id).dbid.set(root.DBID.pyval)
     endo = root.find("CENSUS/SCALE[@id='66']/SCORE").pyval
     if endo == 1:
         endo = "{:.0f} endorsement".format(endo)
     else:
         endo = "{:.0f} endorsements".format(endo)
     founded = root.FOUNDED.pyval or "in Antiquity"
     is_zday = self._is_zday(ctx.message,
                             dev=ctx.author.id == 215640856839979008)
     embed = ProxyEmbed(
         title=root.FULLNAME.text,
         url="https://www.nationstates.net/nation={}".format(
             root.get("id")),
         description="[{}](https://www.nationstates.net/region={})"
         " | {} {} | Founded {}".format(
             root.REGION.text,
             "_".join(root.REGION.text.lower().split()),
             self._illion(root.POPULATION.pyval),
             root["DEMONYM2PLURAL"].text,
             founded,
         ),
         timestamp=datetime.utcfromtimestamp(root.LASTLOGIN.pyval),
         colour=0x8BBC21 if is_zday else await ctx.embed_colour(),
     )
     embed.set_author(name="NationStates",
                      url="https://www.nationstates.net/")
     embed.set_thumbnail(url=root.FLAG.text)
     embed.add_field(
         name=root.CATEGORY.text,
         value="{}\t|\t{}\t|\t{}".format(
             root.find("FREEDOM/CIVILRIGHTS"),
             root.find("FREEDOM/ECONOMY"),
             root.find("FREEDOM/POLITICALFREEDOM"),
         ),
         inline=False,
     )
     embed.add_field(
         name=root.UNSTATUS.text,
         value="{} | {:.0f} influence ({})".format(
             endo,
             root.find("CENSUS/SCALE[@id='65']/SCORE").pyval,
             root.INFLUENCE.text),
         inline=False,
     )
     if is_zday:
         embed.add_field(
             name="{}{}".format(
                 (root.ZOMBIE.ZACTION.text or "No Action").title(),
                 " (Unintended)"
                 if root.ZOMBIE.ZACTIONINTENDED.text else "",
             ),
             value="Survivors: {} | Zombies: {} | Dead: {}".format(
                 self._illion(root.ZOMBIE.SURVIVORS),
                 self._illion(root.ZOMBIE.ZOMBIES),
                 self._illion(root.ZOMBIE.DEAD),
             ),
             inline=False,
         )
     embed.add_field(
         name="Cards",
         value=
         ("[{0}'s Deck](https://www.nationstates.net/page=deck/nation={1})\t|"
          "\t[{0}'s Card](https://www.nationstates.net/page=deck/card={2})".
          format(root.NAME.text, n_id, root.DBID.text)),
     )
     embed.set_footer(text="Last Active")
     await embed.send_to(ctx)