Exemple #1
0
 def __call__(self, value):
     try:
         value = int(value)
     except (ValueError, TypeError):
         raise ValidateError(_(u"Value should be int"))
     if abs(value) > self.MAX_8_BYTES_SIGNED_INTEGER:
         raise ValidateError(_(u"Value should be smaller than {}"), self.MAX_8_BYTES_SIGNED_INTEGER)
     return value
Exemple #2
0
 def on_feedback_init(self,*largs):
     from utils.format import get_format
     self.e=CargandoLayout()
     self.e.lbl=_('Cargando')
     self.popup = Popup(title_size=get_format('font14'),title=_('Cargando'),
                   content=self.e,
                   size_hint=(None, None), size=(400, 150),auto_dismiss=False)
     self.popup.open()
Exemple #3
0
    def __call__(self, value):
        if isinstance(value, str) and self.MONEY_REGEXP.match(value):
            if self.positive_only and value.startswith("-"):
                raise ValidateError(_("Amount should be positive"))
            elif self.negative_only and not value.startswith("-"):
                raise ValidateError(_("Amount should be negative"))
            return value

        raise ValidateError(_("Money format is xx.xx"))
Exemple #4
0
    def __call__(self, value):
        try:
            value = int(value)
        except ValueError:
            raise ValidateError(_('{} should be integer'), str(value))

        if self.min is not None and value < self.min:
            raise ValidateError(_("Value should be greater than {}"), self.min)
        if self.max is not None and value > self.max:
            raise ValidateError(_("Value should be less than {}"), self.max)

        return value
Exemple #5
0
        def validator(element, scheme=reference_scheme):
            if callable(scheme):
                return scheme(element)

            elif isinstance(scheme, tuple):
                for type_validator in scheme:
                    return validator(element, type_validator)

            elif isinstance(element, list):
                if isinstance(scheme, list):
                    assert scheme
                    return [validator(part, scheme[0]) for part in element]

            elif isinstance(element, dict):
                if isinstance(scheme, dict):
                    assert scheme
                    try:
                        dct = {}
                        for key, value in scheme.items():
                            if key not in element:
                                if value is None or isinstance(value, tuple) and None in value:
                                    continue
                                else:
                                    raise ValidateError(_("Field {} is required"), key)
                            if element[key] is None:
                                dct[key] = None
                            else:
                                try:
                                    dct[key] = validator(element[key], value)
                                except ValidateError as exc:
                                    error = ValidateError(str(exc))
                                    error.subname = key
                                    raise error
                        return dct
                    except KeyError:
                        pass

            elif scheme is str:
                if isinstance(element, str):
                    return element

            elif scheme in (int, float):
                if isinstance(element, scheme):
                    return element

            elif element == scheme:
                return element

            raise ValidateError(_("Unexpected element {}"), repr(element))
Exemple #6
0
    def extract_value(name, type_, default_params, incoming_params):
        """
        Extracts value from the incoming arguments and does some decoding if necessary. It does not validates,
        it just extracts.

        :param str name: The name of an argument you want to extracts
        :param ParameterType type_: Validator for the parameter (actually it does not validates, just put some
            internal logic for parameter requiring).
        :param dict default_params: Default parameters in case if something is absent
        :param dict incoming_params: Incoming parameters.
        :param bool is_json: This flags detects the reason of incoming_params. Were they extracted from JSON or not.

        :return Value.
        """
        if name == ParameterType.TOKEN_NAME:
            token_name = ADMIN_TOKEN_NAME if request_api_type() == API_ADMIN else CABINET_TOKEN_NAME
            return request.get_cookie(token_name) or ""

        value = incoming_params.get(name)
        if value is None:
            value = default_params.get(name)

        if value is None and type_.required:
            raise BadRequest(_(u"{} is required"), name)

        return value
Exemple #7
0
    def validate(self, value):
        """
        This method validates given value. It doesn't catch any exception, it is a task of internal executor.

        :param object value: The value we have to validate.
        :return Validated value.
        """
        processed_value = value
        for type_validator in self.validators:
            try:
                processed_value = type_validator(value)
            except ValidateError as exc:
                if self.name != self.TOKEN_NAME:
                    name = self.name
                    if exc.subname:
                        name += "." + exc.subname
                    raise BadParameter(exc, name)
                raise BadRequest(exc)
            except HTTPError as exc:
                raise exc
            except Exception as exc:
                logbook.info(u"Invalid parameter {}: {} ({})".format(self.name, exc, type(exc)))
                logbook.debug("{}", traceback.format_exc())
                if hasattr(type_validator, "__class__"):
                    validator_name = type_validator.__class__.__name__
                else:
                    validator_name = getattr(type_validator, "__name__", "<unknown type>")

                raise BadRequest(
                    _(u"Invalid parameter {}. It should have type {}"),
                    self.name, validator_name)
        return processed_value
Exemple #8
0
 def __call__(self, value):
     normalized_value = value.replace(u"-", u"_")
     try:
         BabelLocale.parse(normalized_value)
         return normalized_value
     except (ValueError, UnknownLocaleError):
         raise ValidateError(_(u"Incorrect locale {}"), value)
Exemple #9
0
    def __call__(self, value):
        matcher = Time.TIME_REGEXP.match(value)
        if not matcher:
            raise ValidateError(_("Incorrect time format"))

        matcher = matcher.groupdict()

        return 3600 * int(matcher["hours"]) + 60 * int(matcher["minutes"])
Exemple #10
0
 def __call__(self, value):
     value = self.fix_case(value)
     if value not in self.values:
         raise ValidateError(
             _(u"value should one from list: {}"),
             u",".join(map(str, self.values.keys()))
         )
     return self.values[value]
Exemple #11
0
 def _render(cls, text, context):
     try:
         env = Environment(undefined=StrictUndefined)
         ast = env.parse(text)
         unexpected = meta.find_undeclared_variables(ast) - context.keys()
         if unexpected:
             logbook.warning("Unexpected variables in template: {}. Context: {}, Template: {}",
                             ", ".join(unexpected), context, text)
             raise errors.MessageTemplateError(_("Unexpected variables in template: {}"), ", ".join(unexpected))
         template = Template(text, undefined=StrictUndefined)
         rendered = template.render(context)
         return rendered
     except TemplateSyntaxError as e:
         logbook.exception("Render template error: {}. Context: {}, template: {}", e.message, context, text)
         raise errors.MessageTemplateError(_("Template syntax error: {} at line {}.\nText: {}\nContext: {}"),
                                           e.message, e.lineno, text, context)
     except TemplateError as e:
         logbook.exception("Render template error: {}. Context: {}, template: {}, ", e, context, text)
         raise errors.MessageTemplateError(_("Error while rendering template: %s") % e.message)
Exemple #12
0
 def error(self,titol,msg,trace):
     e=ErrorLayout()
     e.lbl.text=msg
     e.trace.text = trace
     e.btn.text=_('Aceptar')
     from utils.format import get_format
     popup = Popup(title_size=get_format('font14'),title=titol,
                   content=e,
                   size_hint=(None, None), size=(400, 400))
     e.btn.bind(on_press=popup.dismiss)
     popup.open()
Exemple #13
0
 def show_message(self,titol,msg,aceptar_function=None,w=400,h=400):
     e=MessageLayout()
     self.aceptar_function=aceptar_function
     e.lbl.text=msg
     e.btn.text=_('Aceptar')
     from utils.format import get_format
     self.popup = Popup(title_size=get_format('font14'),title=titol,
                   content=e,
                   size_hint=(None, None), size=(w, h))
     e.btn.bind(on_press=self.on_press_aceptar)
     self.popup.open()
Exemple #14
0
    def movie_file(self, filepath):
        self.filepath = filepath
        self.parseFile(filepath)

        self.media_width = self.media_info.get("video_width") or DEFAULT_WIDTH
        self.media_height = self.media_info.get("video_height") or DEFAULT_HEIGHT
        self.media_duration = self.media_info.get("general_duration") or 0
        self.media_size = int(self.media_info.get("general_size") or 0)
        self.media_type = self.media_info.get("general_extension") or  _("Unknown")
        self.media_width = int(self.media_width) + 2 * WINDOW_GLOW_RADIUS
        self.media_height = int(self.media_height) + 2 * WINDOW_GLOW_RADIUS
        self.media_duration = int(self.media_duration)
    def movie_file(self, filepath):
        self.filepath = filepath
        self.parseFile(filepath)

        integer = lambda x: int(float(x)) if x else 0

        self.media_width = integer(self.media_info.get("video_width"))
        self.media_height = integer(self.media_info.get("video_height"))
        self.media_duration = integer(self.media_info.get("general_duration"))
        self.media_size = integer(self.media_info.get("general_size"))
        self.media_type = self.media_info.get("general_extension") or _("Unknown")
        self.media_duration = integer(self.media_duration)
Exemple #16
0
    def __call__(self, field):
        order = 1
        if field.startswith("-"):
            order = -1
            field = field[1:]
        if self.fields:
            if field not in self.fields:
                raise ValidateError(
                    _("Invalid format. Expected '[-]field_name', where field_name one of: {}"),
                    self.fields
                )

        return field, order
Exemple #17
0
    def __call__(self, value):
        if not value or '@' not in value:
            raise ValidateError(_(u"Email must include @ symbol"))

        user_part, domain_part = value.rsplit('@', 1)

        if not self.USER_REGEX.match(user_part):
            raise ValidateError(_(u"mail box in email is incorrect"))

        if domain_part not in self.DOMAIN_WHITELIST and not self.DOMAIN_REGEX.match(domain_part):
            # Try for possible IDN domain-part
            try:
                domain_part = domain_part.encode('idna').decode('ascii')
                if not self.DOMAIN_REGEX.match(domain_part):
                    raise ValidateError(_(u"Domain part of email is incorrect"))
                else:
                    return value
            except UnicodeError:
                pass

            raise ValidateError(_(u"Domain part of email is incorrect"))

        return value
Exemple #18
0
    def __call__(self, value):
        if isinstance(value, str):
            parsed_value = super().__call__(value)
        else:
            parsed_value = value

        if not isinstance(parsed_value, dict):
            raise ValidateError(_(u"{} has to be a dictionary"), value)

        result = {
            self.KEY_VALIDATOR(key): self.VALUE_VALIDATOR(value) for key, value in parsed_value.items()
        }
        if self.requires_default_language and DEFAULT_LANGUAGE not in result:
            raise errors.HasToHaveDefinedNameInDefaultLanguage()
        return result
Exemple #19
0
    def __call__(self, value):
        original_value = value
        if isinstance(value, str):
            j = JSON.to_json(value)
            if j is JSON.NOT_JSON or not isinstance(j, list):
                value = value.split(self.delimiter)
            else:
                value = j

        if not isinstance(value, list):
            logbook.info("Value '{}' can't be decoded as json list, or delimiter list (delimiter '{}')",
                         original_value, self.delimiter)
            raise ValidateError(_('list is expected'))

        return [self.validator(element) for element in value]
Exemple #20
0
    def __init__(self, center=False):
        QQuickView.__init__(self)
        self._center_request_count = 1 if center else 0
        surface_format = QSurfaceFormat()
        surface_format.setAlphaBufferSize(8)

        self.setColor(QColor(0, 0, 0, 0))
        self.setMinimumSize(QSize(MINIMIZE_WIDTH, MINIMIZE_HEIGHT))
        self.setResizeMode(QQuickView.SizeRootObjectToView)
        self.setFormat(surface_format)
        self.setFlags(Qt.FramelessWindowHint)

        self.staysOnTop = False
        self.qml_context = self.rootContext()
        self.setTitle(_("Deepin Movie"))
        self.setIcon(icon_from_theme("Deepin", "deepin-movie"))

        self.setDeepinWindowShadowHint(self.windowGlowRadius)
Exemple #21
0
 def check_is_instance_of(func_name, value):
     if not isinstance(value, types):
         raise RQInvalidArgument(
             _(u"function {}: invalid {} argument, expect a value of type {}, got {} (type: {})"
               ).format(func_name, self._arg_name, types, value,
                        type(value)))
Exemple #22
0
 def raise_not_valid_future_error(self, func_name, arg_name, value):
     raise RQInvalidArgument(
         _(u"function {}: invalid {} argument, expect a valid future instrument/order_book_id/symbol, "
           u"got {} (type: {})").format(func_name, self._arg_name, value,
                                        type(value)))
Exemple #23
0
    async def date(self, ctx):
        _(
            """Take your partner on a date to increase *their* lovescore. To increase your own lovescore, your partner should go on a date with you.

            The lovescore gained from dates can range from 10 to 150 in steps of 10.

            Only players who are married can use this command.
            (This command has a cooldown of 12 hours.)"""
        )
        num = random.randint(1, 15) * 10
        marriage = ctx.character_data["marriage"]
        if not marriage:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("You are not married yet."))
        await self.bot.pool.execute(
            'UPDATE profile SET "lovescore"="lovescore"+$1 WHERE "user"=$2;',
            num,
            marriage,
        )
        await self.bot.cache.update_profile_cols_rel(marriage, lovescore=num)

        partner = await self.bot.get_user_global(marriage)
        scenario = random.choice(
            [
                _("You and {partner} went on a nice candlelit dinner."),
                _("You and {partner} had stargazed all night."),
                _("You and {partner} went to a circus that was in town."),
                _("You and {partner} went out to see a romantic movie."),
                _("You and {partner} went out to get ice cream."),
                _("You and {partner} had an anime marathon."),
                _("You and {partner} went for a spontaneous hiking trip."),
                _("You and {partner} decided to visit Paris."),
                _("You and {partner} went ice skating together."),
            ]
        ).format(partner=(partner.mention if partner else _("Unknown User")))
        text = _("This increased their lovescore by {num}").format(num=num)
        await ctx.send(f"{scenario} {text}")
Exemple #24
0
 async def myclass(self, ctx):
     _("""Show your class(es) and their added benefits, sent as images.""")
     if (classes := ctx.character_data["class"]) == ["No Class", "No Class"]:
         return await ctx.send("You haven't got a class yet.")
Exemple #25
0
    async def familyevent(self, ctx):
        _(
            """Allow your children to do something, this includes a multitude of events.

            Every time you or your partner uses this command, your children:
              - have an 8/23 chance to grow older by one year
              - have a 4/23 chance to be renamed
              - have a 4/23 chance to take up to 1/64th of your money
              - have a 4/23 chance to give you up to 1/64th of your current money extra
              - have a 2/23 chance to find a random crate for you:
                + 500/761 (65%) chance for a common crate
                + 200/761 (26%) chance for an uncommon crate
                + 50/761 (6%) chance for a rare crate
                + 10/761 (1%) chance for a magic crate
                + 1/761 (0.1%) chance for a legendary crate
              - have a 1/23 chance to die

            In each event you will know what happened.

            Only players who are married and have children can use this command.
            (This command has a cooldown of 30 minutes.)"""
        )
        children = await self.bot.pool.fetch(
            'SELECT * FROM children WHERE ("mother"=$1 AND "father"=$2) OR ("father"=$1'
            ' AND "mother"=$2);',
            ctx.author.id,
            ctx.character_data["marriage"],
        )
        if not children:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("You don't have kids yet."))
        target = random.choice(children)
        event = random.choice(
            ["death"]
            + ["age"] * 8
            + ["namechange"] * 4
            + ["crate"] * 2
            + ["moneylose"] * 4
            + ["moneygain"] * 4
        )
        if event == "death":
            cause = random.choice(
                [
                    _("They died because of a shampoo overdose!"),
                    _("They died of lovesickness..."),
                    _("They've died of age."),
                    _("They died of loneliness."),
                    _("A horde of goblins got them."),
                    _(
                        "They have finally decided to move out after all these years,"
                        " but couldn't survive a second alone."
                    ),
                    _("Spontaneous combustion removed them from existence."),
                    _("While exploring the forest, they have gotten lost."),
                    _("They've left through a portal into another dimension..."),
                    _(
                        "The unbearable pain of stepping on a Lego\© brick killed them."  # noqa
                    ),
                    _("You heard a landmine going off nearby..."),
                    _("They have been abducted by aliens!"),
                    _("The Catholic Church got them..."),
                    _("They starved after becoming a communist."),
                ]
            )
            await self.bot.pool.execute(
                'DELETE FROM children WHERE "name"=$1 AND (("mother"=$2 AND'
                ' "father"=$4) OR ("father"=$2 AND "mother"=$4)) AND "age"=$3;',
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{name} died at the age of {age}! {cause}").format(
                    name=target["name"], age=target["age"], cause=cause
                )
            )
        elif event == "moneylose":
            cause = random.choice(
                [
                    _(
                        "fell in love with a woman on the internet, but the woman was a"
                        " man and stole their money."
                    ),
                    _("has been arrested and had to post bail."),
                    _("bought fortnite skins with your credit card."),
                    _("decided to become communist and gave the money to others."),
                    _("was caught pickpocketing and you had to pay the fine."),
                    _("gave it to a beggar."),
                    _("borrowed it to attend the local knights course."),
                    _("spent it in the shop."),
                    _("bought some toys."),
                    _("has gambling addiction and lost the money..."),
                ]
            )
            money = random.randint(0, int(ctx.character_data["money"] / 64))
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                    money,
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=ctx.author.id,
                    to=2,
                    subject="money",
                    data={"Amount": -money},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=-money)

            return await ctx.send(
                _("You lost ${money} because {name} {cause}").format(
                    money=money, name=target["name"], cause=cause
                )
            )
        elif event == "moneygain":
            cause = random.choice(
                [
                    _("finally found a job!"),
                    _("won a lottery."),
                    _("sold their toys."),
                    _("got money from another kid that decided to become communist."),
                    _("stole it from a traveller."),
                    _("finished a quest with a money reward."),
                    _("used dark magic to summon some money."),
                    _("looted a local warehouse and sold the wares."),
                    _("solved an enigma with a money reward."),
                ]
            )
            money = random.randint(0, int(ctx.character_data["money"] / 64))
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                    money,
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=1,
                    to=ctx.author.id,
                    subject="money",
                    data={"Amount": money},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=money)
            return await ctx.send(
                _("{name} gave you ${money}, they {cause}").format(
                    name=target["name"], money=money, cause=cause
                )
            )
        elif event == "crate":
            type_ = random.choice(
                ["common"] * 500
                + ["uncommon"] * 200
                + ["rare"] * 50
                + ["magic"] * 10
                + ["legendary"]
            )
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    f'UPDATE profile SET "crates_{type_}"="crates_{type_}"+1 WHERE'
                    ' "user"=$1;',
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=ctx.author.id,
                    to=2,
                    subject="crates",
                    data={"Rarity": type_, "Amount": 1},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(
                ctx.author.id, **{f"crates_{type_}": 1}
            )
            emoji = getattr(self.bot.cogs["Crates"].emotes, type_)
            return await ctx.send(
                _("{name} found a {emoji} {type_} crate for you!").format(
                    name=target["name"], emoji=emoji, type_=type_
                )
            )
        elif event == "age":
            await self.bot.pool.execute(
                'UPDATE children SET "age"="age"+1 WHERE "name"=$1 AND (("mother"=$2'
                ' AND "father"=$4) OR ("father"=$2 AND "mother"=$4)) AND "age"=$3;',
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{name} is now {age} years old.").format(
                    name=target["name"], age=target["age"] + 1
                )
            )
        elif event == "namechange":
            names = [c["name"] for c in children]
            names.remove(target["name"])

            def check(msg):
                return (
                    msg.author.id in [ctx.author.id, ctx.character_data["marriage"]]
                    and msg.channel.id == ctx.channel.id
                )

            name = None
            while not name:
                await ctx.send(
                    _(
                        "{name} can be renamed! Within 30 seconds, enter a new"
                        " name:\nType `cancel` to leave the name unchanged."
                    ).format(name=target["name"])
                )
                try:
                    msg = await self.bot.wait_for("message", check=check, timeout=30)
                    name = msg.content.replace("@", "@\u200b")
                except asyncio.TimeoutError:
                    return await ctx.send(_("You didn't enter a name."))
                if name.lower() == "cancel":
                    return await ctx.send(_("You didn't want to rename."))
                if len(name) == 0 or len(name) > 20:
                    await ctx.send(_("Name must be 1 to 20 characters only."))
                    name = None
                    continue
                if name in names:
                    await ctx.send(
                        _(
                            "One of your children already has that name, please choose"
                            " another one."
                        )
                    )
                    name = None
                    continue
                try:
                    if not await ctx.confirm(
                        _(
                            '{author} Are you sure you want to rename "{old_name}" to'
                            ' "{new_name}"?'
                        ).format(
                            author=ctx.author.mention,
                            old_name=target["name"],
                            new_name=name,
                        )
                    ):
                        await ctx.send(
                            _('You didn\'t change the name to "{new_name}".').format(
                                new_name=name
                            )
                        )
                        name = None
                        await self.bot.set_cooldown(ctx, 1800)
                except self.bot.paginator.NoChoice:
                    await ctx.send(_("You didn't confirm."))
                    name = None

            if name == target["name"]:
                return await ctx.send(_("You didn't change their name."))
            await self.bot.pool.execute(
                'UPDATE children SET "name"=$1 WHERE "name"=$2 AND (("mother"=$3 AND'
                ' "father"=$5) OR ("father"=$3 AND "mother"=$5)) AND "age"=$4;',
                name,
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{old_name} is now called {new_name}.").format(
                    old_name=target["name"], new_name=name
                )
            )
Exemple #26
0
    async def spoil(self, ctx, item: IntFromTo(1, 40) = None):
        _(
            """`[item]` - The item to buy, a whole number from 1 to 40; if not given, displays the list of items

            Buy something for your partner to increase *their* lovescore. To increase your own lovescore, your partner should spoil you.

            Please note that these items are not usable and do not have an effect on gameplay, beside increasing lovescore.

            Only players who are married can use this command."""
        )
        items = [
            (_("Dog :dog2:"), 50),
            (_("Cat :cat2:"), 50),
            (_("Cow :cow2:"), 75),
            (_("Penguin :penguin:"), 100),
            (_("Unicorn :unicorn:"), 1000),
            (_("Potato :potato:"), 1),
            (_("Sweet potato :sweet_potato:"), 2),
            (_("Peach :peach:"), 5),
            (_("Ice Cream :ice_cream:"), 10),
            (_("Bento Box :bento:"), 50),
            (_("Movie Night :ticket:"), 75),
            (_("Video Game Night :video_game:"), 10),
            (_("Camping Night :fishing_pole_and_fish:"), 15),
            (_("Couple Competition :trophy:"), 30),
            (_("Concert Night :musical_keyboard:"), 100),
            (_("Bicycle :bike:"), 100),
            (_("Motorcycle :motorcycle:"), 250),
            (_("Car :red_car:"), 300),
            (_("Private Jet :airplane:"), 1000),
            (_("Space Rocket :rocket:"), 10000),
            (_("Credit Card :credit_card:"), 20),
            (_("Watch :watch:"), 100),
            (_("Phone :iphone:"), 100),
            (_("Bed :bed:"), 500),
            (_("Home films :projector:"), 750),
            (_("Satchel :school_satchel:"), 25),
            (_("Purse :purse:"), 30),
            (_("Shoes :athletic_shoe:"), 150),
            (_("Casual Attire :shirt:"), 200),
            (_("Ring :ring:"), 1000),
            (_("Balloon :balloon:"), 10),
            (_("Flower Bouquet :bouquet:"), 25),
            (_("Expensive Chocolates :chocolate_bar:"), 40),
            (_("Declaration of Love :love_letter:"), 50),
            (_("Key to Heart :key2:"), 100),
            (_("Ancient Vase :amphora:"), 15000),
            (_("House :house:"), 25000),
            (_("Super Computer :computer:"), 50000),
            (_("Precious Gemstone Collection :gem:"), 75000),
            (_("Planet :earth_americas:"), 1_000_000),
        ]
        text = _("Price")
        items_str = "\n".join(
            [
                f"{idx + 1}.) {item} ... {text}: **${price}**"
                for idx, (item, price) in enumerate(items)
            ]
        )
        if not item:
            text = _(
                "To buy one of these items for your partner, use `{prefix}spoil shopid`"
            ).format(prefix=ctx.prefix)
            return await ctx.send(f"{items_str}\n\n{text}")
        item = items[item - 1]
        if ctx.character_data["money"] < item[1]:
            return await ctx.send(_("You are too poor to buy this."))
        if not ctx.character_data["marriage"]:
            return await ctx.send(_("You're not married yet."))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "lovescore"="lovescore"+$1 WHERE "user"=$2;',
                item[1],
                ctx.character_data["marriage"],
            )
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                item[1],
                ctx.author.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=ctx.author.id,
                to=2,
                subject="money",
                data={"Amount": item[1]},
                conn=conn,
            )
        await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=-item[1])
        await self.bot.cache.update_profile_cols_rel(
            ctx.character_data["marriage"], lovescore=item[1]
        )
        await ctx.send(
            _(
                "You bought a **{item}** for your partner and increased their love"
                " score by **{points}** points!"
            ).format(item=item[0], points=item[1])
        )
        user = await self.bot.get_user_global(ctx.character_data["marriage"])
        if not user:
            return await ctx.send(
                _("Failed to DM your spouse, could not find their Discord account")
            )
        await user.send(
            "**{author}** bought you a **{item}** and increased your love score by"
            " **{points}** points!".format(
                author=ctx.author, item=item[0], points=item[1]
            )
        )
Exemple #27
0
 def __call__(self, value):
     value = float(value)
     if value < 0:
         raise ValidateError(_(u"{} should be positive float"), value)
     return value
Exemple #28
0
class Profile(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @checks.has_no_char()
    @user_cooldown(3600)
    @commands.command(aliases=["new", "c", "start"],
                      brief=_("Create a new character"))
    @locale_doc
    async def create(self, ctx, *, name: str = None):
        _("""`[name]` - The name to give your character; will be interactive if not given

            Create a new character and start playing IdleRPG.

            By creating a character, you agree to the [bot rules](https://wiki.idlerpg.xyz/index.php?title=Rules#botrules).
            No idea where to go from here? Check out our [tutorial](https://idlerpg.xyz/tutorial/).
            If you still have questions afterward, feel free to ask us on the official [support server](https://support.idlerpg.xyz/).

            (This command has a cooldown of 1 hour.)""")
        if not name:
            await ctx.send(
                _("""\
What shall your character's name be? (Minimum 3 Characters, Maximum 20)

**Please note that with the creation of a character, you agree to these rules:**
1) Only up to two characters per individual
2) No abusing or benefiting from bugs or exploits
3) Be friendly and kind to other players
4) Trading in-game items or currency for real money or items directly comparable to currency is forbidden

IdleRPG is a global bot, your characters are valid everywhere"""))

            def mycheck(amsg):
                return amsg.author == ctx.author and amsg.channel == ctx.channel

            try:
                name = await self.bot.wait_for("message",
                                               timeout=60,
                                               check=mycheck)
            except asyncio.TimeoutError:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(_("Timeout expired. Please retry!"))
            name = name.content
        else:
            if not await ctx.confirm(
                    _("""\
**Please note that with the creation of a character, you agree to these rules:**
1) Only up to two characters per individual
2) No abusing or benefiting from bugs or exploits
3) Be friendly and kind to other players
4) Trading in-game items or currency for real money or items directly comparable to currency is forbidden

IdleRPG is a global bot, your characters are valid everywhere""")):
                return await ctx.send(
                    _("Creation of your character cancelled."))
        if len(name) > 2 and len(name) < 21:
            if "`" in name:
                return await ctx.send(
                    _("Illegal character (`) found in the name. Please try again and"
                      " choose another name."))

            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    "INSERT INTO profile VALUES ($1, $2, $3, $4);",
                    ctx.author.id,
                    name,
                    100,
                    0,
                )
                await self.bot.create_item(
                    name=_("Starter Sword"),
                    value=0,
                    type_="Sword",
                    damage=3.0,
                    armor=0.0,
                    owner=ctx.author,
                    hand="any",
                    equipped=True,
                    conn=conn,
                )
                await self.bot.create_item(
                    name=_("Starter Shield"),
                    value=0,
                    type_="Shield",
                    damage=0.0,
                    armor=3.0,
                    owner=ctx.author,
                    hand="left",
                    equipped=True,
                    conn=conn,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=1,
                    to=ctx.author.id,
                    subject="money",
                    data={"Amount": 100},
                    conn=conn,
                )
            await ctx.send(
                _("Successfully added your character **{name}**! Now use"
                  " `{prefix}profile` to view your character!").format(
                      name=name, prefix=ctx.prefix))
        elif len(name) < 3 or len(name) > 20:
            await ctx.send(
                _("Character names must be at least 3 characters and up to 20."
                  ))
            await self.bot.reset_cooldown(ctx)

    @commands.command(aliases=["me", "p"], brief=_("View someone's profile"))
    @locale_doc
    async def profile(self, ctx, *, person: User = Author):
        _("""`[person]` - The person whose profile to view; defaults to oneself

            View someone's profile. This will send an image.
            For an explanation what all the fields mean, see [this picture](https://wiki.idlerpg.xyz/images/3/35/Profile_explained.png)"""
          )
        await ctx.trigger_typing()
        targetid = person.id
        async with self.bot.pool.acquire() as conn:
            profile = await self.bot.cache.get_profile(targetid, conn=conn)
            if not profile:
                return await ctx.send(
                    _("**{person}** does not have a character.").format(
                        person=person))
            items = await self.bot.get_equipped_items_for(targetid, conn=conn)
            mission = await self.bot.get_adventure(targetid)
            guild = await conn.fetchval(
                'SELECT name FROM guild WHERE "id"=$1;', profile["guild"])
        v1 = sum(i["damage"] for i in items)
        v2 = sum(i["armor"] for i in items)
        damage, armor = await self.bot.get_damage_armor_for(
            targetid,
            items=items,
            classes=profile["class"],
            race=profile["race"])
        extras = (damage - v1, armor - v2)
        sworddmg = f"{v1}{' (+' + str(extras[0]) + ')' if extras[0] else ''}"
        shielddef = f"{v2}{' (+' + str(extras[1]) + ')' if extras[1] else ''}"

        right_hand = "None Equipped"
        left_hand = "None Equipped"

        any_count = sum(1 for i in items if i["hand"] == "any")
        if len(items) == 2 and any_count == 1 and items[0]["hand"] == "any":
            items = [items[1], items[0]]

        for i in items:
            if i["hand"] == "both":
                right_hand, left_hand = i["name"], i["name"]
            elif i["hand"] == "left":
                left_hand = i["name"]
            elif i["hand"] == "right":
                right_hand = i["name"]
            elif i["hand"] == "any":
                if right_hand == "None Equipped":
                    right_hand = i["name"]
                else:
                    left_hand = i["name"]

        color = profile["colour"]
        color = [color["red"], color["green"], color["blue"], color["alpha"]]
        classes = [class_from_string(c) for c in profile["class"]]
        icons = [
            c.get_class_line_name().lower() if c else "none" for c in classes
        ]

        url = f"{self.bot.config.external.okapi_url}/api/genprofile"

        async with self.bot.trusted_session.post(
                url,
                json={
                    "name":
                    profile["name"],
                    "color":
                    color,
                    "image":
                    profile["background"],
                    "race":
                    profile["race"],
                    "classes":
                    profile["class"],
                    "damage":
                    sworddmg,
                    "defense":
                    shielddef,
                    "sword_name":
                    right_hand,
                    "shield_name":
                    left_hand,
                    "level":
                    f"{rpgtools.xptolevel(profile['xp'])}",
                    "money":
                    f"{profile['money']}",
                    "pvp_wins":
                    f"{profile['pvpwins']}",
                    "marriage":
                    i if (i := await rpgtools.lookup(
                        self.bot, profile["marriage"], return_none=True)) else
                    _("Not Married"),
                    "guild":
                    guild or _("No Guild"),
                    "god":
                    profile["god"] or _("No God"),
                    "icons":
                    icons,
                    "adventure":
                    ("Adventure"
                     f" {mission[0]}\n{mission[1] if not mission[2] else _('Finished')}"
                     ) if mission else _("No Mission"),
                },
        ) as req:
            if req.status == 200:
                img = BytesIO(await req.read())
            else:
                # Error, means try reading the response JSON error
                try:
                    error_json = await req.json()
                    return await ctx.send(
                        _("There was an error processing your image. Reason: {reason} ({detail})"
                          ).format(reason=error_json["reason"],
                                   detail=error_json["detail"]))
                except ContentTypeError:
                    return await ctx.send(
                        _("Unexpected internal error when generating image."))
                except Exception:
                    return await ctx.send(
                        _("Unexpected error when generating image."))
        await ctx.send(file=discord.File(fp=img, filename="Profile.png"))
Exemple #29
0
 def __call__(self, value):
     language = super().__call__(value)
     if language not in available_languages():
         raise ValidateError(_(u"Language {} is not active"), value)
     return language
Exemple #30
0
    async def profile2(self, ctx, *, target: User = Author):
        _("""`[target]` - The person whose profile to view

            View someone's profile. This will send an embed rather than an image and is usually faster."""
          )
        rank_money, rank_xp = await self.bot.get_ranks_for(target)

        items = await self.bot.get_equipped_items_for(target)
        async with self.bot.pool.acquire() as conn:
            p_data = await self.bot.cache.get_profile(target.id, conn=conn)
            if not p_data:
                return await ctx.send(
                    _("**{target}** does not have a character.").format(
                        target=target))
            mission = await self.bot.get_adventure(target)
            guild = await conn.fetchval(
                'SELECT name FROM guild WHERE "id"=$1;', p_data["guild"])
        try:
            colour = p_data["colour"]
            colour = discord.Colour.from_rgb(colour["red"], colour["green"],
                                             colour["blue"])
        except ValueError:
            colour = 0x000000
        if mission:
            timeleft = str(
                mission[1]).split(".")[0] if not mission[2] else "Finished"

        right_hand = None
        left_hand = None

        any_count = sum(1 for i in items if i["hand"] == "any")
        if len(items) == 2 and any_count == 1 and items[0]["hand"] == "any":
            items = [items[1], items[0]]

        for i in items:
            if i["hand"] == "both":
                right_hand, left_hand = i, i
            elif i["hand"] == "left":
                left_hand = i
            elif i["hand"] == "right":
                right_hand = i
            elif i["hand"] == "any":
                if right_hand is None:
                    right_hand = i
                else:
                    left_hand = i

        right_hand = (
            f"{right_hand['name']} - {right_hand['damage'] + right_hand['armor']}"
            if right_hand else _("None Equipped"))
        left_hand = (
            f"{left_hand['name']} - {left_hand['damage'] + left_hand['armor']}"
            if left_hand else _("None Equipped"))
        level = rpgtools.xptolevel(p_data["xp"])
        em = discord.Embed(colour=colour, title=f"{target}: {p_data['name']}")
        em.set_thumbnail(url=target.avatar_url)
        em.add_field(
            name=_("General"),
            value=_("""\
**Money**: `${money}`
**Level**: `{level}`
**Class**: `{class_}`
**Race**: `{race}`
**PvP Wins**: `{pvp}`
**Guild**: `{guild}`""").format(
                money=p_data["money"],
                level=level,
                class_="/".join(p_data["class"]),
                race=p_data["race"],
                pvp=p_data["pvpwins"],
                guild=guild,
            ),
        )
        em.add_field(
            name=_("Ranks"),
            value=_("**Richest**: `{rank_money}`\n**XP**: `{rank_xp}`").format(
                rank_money=rank_money, rank_xp=rank_xp),
        )
        em.add_field(
            name=_("Equipment"),
            value=_("Right Hand: {right_hand}\nLeft Hand: {left_hand}").format(
                right_hand=right_hand, left_hand=left_hand),
        )
        if mission:
            em.add_field(name=_("Mission"), value=f"{mission[0]} - {timeleft}")
        await ctx.send(embed=em)
Exemple #31
0
    async def profile(self, ctx, *, person: User = Author):
        _("""`[person]` - The person whose profile to view; defaults to oneself

            View someone's profile. This will send an image.
            For an explanation what all the fields mean, see [this picture](https://wiki.idlerpg.xyz/images/3/35/Profile_explained.png)"""
          )
        await ctx.trigger_typing()
        targetid = person.id
        async with self.bot.pool.acquire() as conn:
            profile = await self.bot.cache.get_profile(targetid, conn=conn)
            if not profile:
                return await ctx.send(
                    _("**{person}** does not have a character.").format(
                        person=person))
            items = await self.bot.get_equipped_items_for(targetid, conn=conn)
            mission = await self.bot.get_adventure(targetid)
            guild = await conn.fetchval(
                'SELECT name FROM guild WHERE "id"=$1;', profile["guild"])
        v1 = sum(i["damage"] for i in items)
        v2 = sum(i["armor"] for i in items)
        damage, armor = await self.bot.get_damage_armor_for(
            targetid,
            items=items,
            classes=profile["class"],
            race=profile["race"])
        extras = (damage - v1, armor - v2)
        sworddmg = f"{v1}{' (+' + str(extras[0]) + ')' if extras[0] else ''}"
        shielddef = f"{v2}{' (+' + str(extras[1]) + ')' if extras[1] else ''}"

        right_hand = "None Equipped"
        left_hand = "None Equipped"

        any_count = sum(1 for i in items if i["hand"] == "any")
        if len(items) == 2 and any_count == 1 and items[0]["hand"] == "any":
            items = [items[1], items[0]]

        for i in items:
            if i["hand"] == "both":
                right_hand, left_hand = i["name"], i["name"]
            elif i["hand"] == "left":
                left_hand = i["name"]
            elif i["hand"] == "right":
                right_hand = i["name"]
            elif i["hand"] == "any":
                if right_hand == "None Equipped":
                    right_hand = i["name"]
                else:
                    left_hand = i["name"]

        color = profile["colour"]
        color = [color["red"], color["green"], color["blue"], color["alpha"]]
        classes = [class_from_string(c) for c in profile["class"]]
        icons = [
            c.get_class_line_name().lower() if c else "none" for c in classes
        ]

        url = f"{self.bot.config.external.okapi_url}/api/genprofile"

        async with self.bot.trusted_session.post(
                url,
                json={
                    "name":
                    profile["name"],
                    "color":
                    color,
                    "image":
                    profile["background"],
                    "race":
                    profile["race"],
                    "classes":
                    profile["class"],
                    "damage":
                    sworddmg,
                    "defense":
                    shielddef,
                    "sword_name":
                    right_hand,
                    "shield_name":
                    left_hand,
                    "level":
                    f"{rpgtools.xptolevel(profile['xp'])}",
                    "money":
                    f"{profile['money']}",
                    "pvp_wins":
                    f"{profile['pvpwins']}",
                    "marriage":
                    i if (i := await rpgtools.lookup(
                        self.bot, profile["marriage"], return_none=True)) else
                    _("Not Married"),
                    "guild":
                    guild or _("No Guild"),
                    "god":
                    profile["god"] or _("No God"),
                    "icons":
                    icons,
                    "adventure":
                    ("Adventure"
                     f" {mission[0]}\n{mission[1] if not mission[2] else _('Finished')}"
                     ) if mission else _("No Mission"),
                },
        ) as req:
            if req.status == 200:
                img = BytesIO(await req.read())
            else:
                # Error, means try reading the response JSON error
                try:
                    error_json = await req.json()
                    return await ctx.send(
                        _("There was an error processing your image. Reason: {reason} ({detail})"
                          ).format(reason=error_json["reason"],
                                   detail=error_json["detail"]))
                except ContentTypeError:
                    return await ctx.send(
                        _("Unexpected internal error when generating image."))
                except Exception:
                    return await ctx.send(
                        _("Unexpected error when generating image."))
Exemple #32
0
                try:
                    error_json = await req.json()
                    return await ctx.send(
                        _("There was an error processing your image. Reason: {reason} ({detail})"
                          ).format(reason=error_json["reason"],
                                   detail=error_json["detail"]))
                except ContentTypeError:
                    return await ctx.send(
                        _("Unexpected internal error when generating image."))
                except Exception:
                    return await ctx.send(
                        _("Unexpected error when generating image."))
        await ctx.send(file=discord.File(fp=img, filename="Profile.png"))

    @commands.command(aliases=["p2", "pp"],
                      brief=_("View someone's profile differently"))
    @locale_doc
    async def profile2(self, ctx, *, target: User = Author):
        _("""`[target]` - The person whose profile to view

            View someone's profile. This will send an embed rather than an image and is usually faster."""
          )
        rank_money, rank_xp = await self.bot.get_ranks_for(target)

        items = await self.bot.get_equipped_items_for(target)
        async with self.bot.pool.acquire() as conn:
            p_data = await self.bot.cache.get_profile(target.id, conn=conn)
            if not p_data:
                return await ctx.send(
                    _("**{target}** does not have a character.").format(
                        target=target))
Exemple #33
0
 def check_less_than(func_name, value):
     if value >= high:
         raise RQInvalidArgument(
             _(u"function {}: invalid {} argument, expect a value < {}, got {} (type: {})"
               ).format(func_name, self._arg_name, high, value,
                        type(value)))
Exemple #34
0
    async def propose(self, ctx, partner: MemberWithCharacter):
        _(
            """`<partner>` - A discord User with a character who is not yet married

            Propose to a player for marriage. Once they accept, you are married.

            When married, your partner will get bonuses from your adventures, you can have children, which can do different things (see `{prefix}help familyevent`) and increase your lovescore, which has an effect on the [adventure bonus](https://wiki.idlerpg.xyz/index.php?title=Family#Adventure_Bonus).
            If any of you has children, they will be brought together to one family.

            Only players who are not already married can use this command."""
        )
        if partner == ctx.author:
            return await ctx.send(
                _("You should have a better friend than only yourself.")
            )
        if ctx.character_data["marriage"] != 0 or ctx.user_data["marriage"] != 0:
            return await ctx.send(_("One of you is married."))
        msg = await ctx.send(
            embed=discord.Embed(
                title=_("{author} has proposed for a marriage!").format(
                    author=ctx.disp,
                ),
                description=_(
                    "{author} wants to marry you, {partner}! React with :heart: to"
                    " marry them!"
                ).format(author=ctx.author.mention, partner=partner.mention),
                colour=0xFF0000,
            )
            .set_image(url=ctx.author.avatar_url)
            .set_thumbnail(
                url="http://www.maasbach.com/wp-content/uploads/The-heart.png"
            )
        )
        await msg.add_reaction("\U00002764")

        def reactioncheck(reaction, user):
            return (
                str(reaction.emoji) == "\U00002764"
                and reaction.message.id == msg.id
                and user.id == partner.id
            )

        try:
            _reaction, _user = await self.bot.wait_for(
                "reaction_add", timeout=120.0, check=reactioncheck
            )
        except asyncio.TimeoutError:
            return await ctx.send(_("They didn't want to marry."))
        # check if someone married in the meantime
        check1 = await self.bot.cache.get_profile_col(ctx.author.id, "marriage")
        check2 = await self.bot.cache.get_profile_col(partner.id, "marriage")
        if check1 or check2:
            return await ctx.send(
                _("Either you or your lovee married in the meantime... :broken_heart:")
            )
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "marriage"=$1 WHERE "user"=$2;',
                partner.id,
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE profile SET "marriage"=$1 WHERE "user"=$2;',
                ctx.author.id,
                partner.id,
            )
            await conn.execute(
                'UPDATE children SET "father"=$1 WHERE "father"=0 AND "mother"=$2;',
                partner.id,
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE children SET "father"=$1 WHERE "father"=0 AND "mother"=$2;',
                ctx.author.id,
                partner.id,
            )
        await self.bot.cache.update_profile_cols_abs(ctx.author.id, marriage=partner.id)
        await self.bot.cache.update_profile_cols_abs(partner.id, marriage=ctx.author.id)
        # we give familyevent cooldown to the new partner to avoid exploitation
        await self.bot.set_cooldown(partner.id, 1800, "familyevent")
        await ctx.send(
            _("Aww! :heart: {author} and {partner} are now married!").format(
                author=ctx.author.mention, partner=partner.mention
            )
        )
Exemple #35
0
 def check_greater_than(func_name, value):
     if value <= low:
         raise RQInvalidArgument(
             _(u"function {}: invalid {} argument, expect a value > {}, got {} (type: {})"
               ).format(func_name, self._arg_name, low, value,
                        type(value)))
Exemple #36
0
    async def drink(self, ctx):
        _(
            """Give your pet something to drink. This brings up an interactive menu where you can buy a drink item.

            Only rangers can use this command."""
        )
        items = [
            (_("Some Water"), 10, ":droplet:", 1),
            (_("A bottle of water"), 30, ":baby_bottle:", 2),
            (_("Cocktail"), 50, ":cocktail:", 4),
            (_("Wine"), 150, ":wine_glass:", 10),
            (_("Beer"), 250, ":beer:", 20),
            (_("Vodka"), 800, ":flag_ru:", 50),
            (_("Adrian's Cocktail"), 2000, ":tropical_drink:", 100),
        ]
        item = items[
            await self.bot.paginator.Choose(
                entries=[f"{i[2]} {i[0]} **${i[1]}** -> +{i[3]}" for i in items],
                return_index=True,
                timeout=30,
                title=_("Give your pet something to drink"),
            ).paginate(ctx)
        ]
        if not await has_money(self.bot, ctx.author.id, item[1]):
            return await ctx.send(_("You are too poor to buy this."))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                item[1],
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE pets SET "drink"=CASE WHEN "drink"+$1>=100 THEN 100 ELSE'
                ' "drink"+$1 END WHERE "user"=$2;',
                item[3],
                ctx.author.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=ctx.author.id,
                to=2,
                subject="money",
                data={"Amount": item[1]},
            )
        await ctx.send(
            _(
                "You bought **{item}** for your pet and increased its drinks bar by"
                " **{points}** points."
            ).format(item=f"{item[2]} {item[0]}", points=item[3])
        )
Exemple #37
0
    async def hunt(self, ctx):
        _(
            # xgettext: no-python-format
            """Make your pet hunt an item for you.

            The items stat depends on your pet's level (determined by class evolution) as well as its joy score.
            The lowest base stat your pet can find is three times its level, the highest is 6 times its level.
            Your pet's joy score in percent is multiplied with these base stats.

            For example:
              - Your pet is on level 2, its  joy score is 50.
              - The item's base stats are (3x2) to (6x2), so 6 to 12.
              - Its joy score in percent is multiplied: 50% x 6 to 50% x 12, so 3 to 6

            In this example, your pet can hunt an item with stats 3 to 6. It has a hard cap at 30.
            The item's value will be between 0 and 250.

            Only rangers can use this command.
            (This command has a cooldown until 12am UTC.)"""
        )
        petlvl = self.bot.get_class_grade_from(ctx.character_data["class"], "Ranger")
        joy_multiply = Decimal(ctx.pet_data["joy"] / 100)
        luck_multiply = ctx.character_data["luck"]
        minstat = round(petlvl * 3 * luck_multiply * joy_multiply)
        maxstat = round(petlvl * 6 * luck_multiply * joy_multiply)
        if minstat < 1 or maxstat < 1:
            return await ctx.send(
                _("Your pet is not happy enough to hunt an item. Try making it joyful!")
            )
        item = await self.bot.create_random_item(
            minstat=minstat if minstat < 30 else 30,
            maxstat=maxstat if maxstat < 30 else 30,
            minvalue=1,
            maxvalue=250,
            owner=ctx.author,
        )
        embed = discord.Embed(
            title=_("You gained an item!"),
            description=_("Your pet found an item!"),
            color=0xFF0000,
        )
        embed.set_thumbnail(url=ctx.author.avatar_url)
        embed.add_field(name=_("ID"), value=item["id"], inline=False)
        embed.add_field(name=_("Name"), value=item["name"], inline=False)
        embed.add_field(name=_("Type"), value=item["type"], inline=False)
        if item["type"] == "Shield":
            embed.add_field(name=_("Armor"), value=item["armor"], inline=True)
        else:
            embed.add_field(name=_("Damage"), value=item["damage"], inline=True)
        embed.add_field(name=_("Value"), value=f"${item['value']}", inline=False)
        embed.set_footer(text=_("Your pet needs to recover, wait a day to retry"))
        await ctx.send(embed=embed)
        await self.bot.log_transaction(
            ctx,
            from_=1,
            to=ctx.author.id,
            subject="item",
            data={"Name": item["name"], "Value": item["value"]},
        )
Exemple #38
0
    async def child(self, ctx):
        _(
            # xgettext: no-python-format
            """Have a child with your partner.

            Children on their own don't do much, but `{prefix}familyevent` can effect your money and crates.
            To have a child, your partner has to be on the server to accept the checkbox.

            There is a 50% chance that you will have a child, and a 50% chance to just *have fun* (if you know what I'm saying) and gain between 10 and 50 lovescore.
            When you have a child, there is a 50% chance for it to be a boy and a 50% chance to be a girl.

            Your partner and you can enter a name for your child once the bot prompts you to. (Do not include `{prefix}`)
            If you fail to choose a name in time, the bot will choose one for you from about 500 pre-picked ones.

            For identification purposes, you cannot have two children with the same name in your family, so make sure to pick a unique one.

            Only players who are married can use this command.
            (This command has a cooldown of 1 hour.)"""
        )
        marriage = ctx.character_data["marriage"]
        if not marriage:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("Can't produce a child alone, can you?"))
        async with self.bot.pool.acquire() as conn:
            names = await conn.fetch(
                'SELECT name FROM children WHERE "mother"=$1 OR "father"=$1;',
                ctx.author.id,
            )
            spouse = await self.bot.cache.get_profile_col(
                marriage, "lovescore", conn=conn
            )
        max_, missing = self.get_max_kids(ctx.character_data["lovescore"] + spouse)
        names = [name["name"] for name in names]
        user = await self.bot.get_user_global(marriage)
        if not await ctx.confirm(
            _("{user}, do you want to make a child with {author}?").format(
                user=user.mention, author=ctx.author.mention
            ),
            user=user,
        ):
            return await ctx.send(_("O.o not in the mood today?"))

        if len(names) >= max_:
            return await self.lovescore_up(ctx, marriage, max_, missing, True)

        if random.choice([True, False]):
            return await self.lovescore_up(ctx, marriage, max_, missing, False)
        gender = random.choice(["m", "f"])
        if gender == "m":
            await ctx.send(
                _(
                    "It's a boy! Your night of love was successful! Please enter a name"
                    " for your child."
                )
            )
        elif gender == "f":
            await ctx.send(
                _(
                    "It's a girl! Your night of love was successful! Please enter a"
                    " name for your child."
                )
            )

        def check(msg):
            return (
                msg.author.id in [ctx.author.id, marriage]
                and 1 <= len(msg.content) <= 20
                and msg.channel.id == ctx.channel.id
            )

        name = None
        while not name:
            try:
                msg = await self.bot.wait_for("message", check=check, timeout=30)
                name = msg.content.replace("@", "@\u200b")
            except asyncio.TimeoutError:
                name = await self.get_random_name(gender, names)
                await ctx.send(
                    _("You didn't enter a name, so we chose {name} for you.").format(
                        name=name
                    )
                )
                break
            if name in names:
                await ctx.send(
                    _(
                        "One of your children already has that name, please choose"
                        " another one."
                    )
                )
                name = None
        await self.bot.pool.execute(
            'INSERT INTO children ("mother", "father", "name", "age", "gender")'
            " VALUES ($1, $2, $3, $4, $5);",
            ctx.author.id,
            marriage,
            name,
            0,
            gender,
        )
        await ctx.send(_("{name} was born.").format(name=name))
Exemple #39
0
    async def play(self, ctx):
        _(
            """Play with your pet to raise its joy points. Your pet can gain from 1 to 12 Joy points per play.

            Only rangers can use this command.
            (This command has a cooldown of 6 hours.)"""
        )
        value = random.randint(0, 11) + 1  # On average, it'll stay as is
        await self.bot.pool.execute(
            'UPDATE pets SET "joy"=CASE WHEN "joy"+$1>=100 THEN 100 ELSE "joy"+$1 END'
            ' WHERE "user"=$2;',
            value,
            ctx.author.id,
        )
        await ctx.send(
            _(
                "You have been {activity} with your pet and it gained **{value}** joy!"
            ).format(
                activity=random.choice(
                    [
                        _("playing football :soccer:"),
                        _("playing American football :football:"),
                        _("playing rugby :rugby_football:"),
                        _("playing basketball :basketball:"),
                        _("playing tennis :tennis:"),
                        _("playing ping-pong :ping_pong:"),
                        _("boxing :boxing_glove:"),
                        _("skiing :ski:"),
                    ]
                ),
                value=value,
            )
        )
Exemple #40
0
    async def family(self, ctx):
        _("""View your children. This will display their name, age and gender.""")
        marriage = ctx.character_data["marriage"]
        children = await self.bot.pool.fetch(
            'SELECT * FROM children WHERE ("mother"=$1 AND "father"=$2) OR ("father"=$1'
            ' AND "mother"=$2);',
            ctx.author.id,
            marriage,
        )

        additional = (
            _("{amount} children").format(amount=len(children))
            if len(children) != 1
            else _("one child")
        )
        em = discord.Embed(
            title=_("Your family, {additional}.").format(additional=additional),
            description=_("{author}'s family").format(author=ctx.author.mention)
            if not marriage
            else _("Family of {author} and <@{marriage}>").format(
                author=ctx.author.mention, marriage=marriage
            ),
        )
        if not children:
            em.add_field(
                name=_("No children yet"),
                value=_("Use `{prefix}child` to make one!").format(prefix=ctx.prefix)
                if marriage
                else _(
                    "Get yourself a partner and use `{prefix}child` to make one!"
                ).format(prefix=ctx.prefix),
            )
        if len(children) <= 5:
            for child in children:
                em.add_field(
                    name=child["name"],
                    value=_("Gender: {gender}, Age: {age}").format(
                        gender=child["gender"], age=child["age"]
                    ),
                    inline=False,
                )
            em.set_thumbnail(url=ctx.author.avatar_url)
            await ctx.send(embed=em)
        else:
            embeds = []
            children_lists = list(chunks(children, 9))
            for small_list in children_lists:
                em = discord.Embed(
                    title=_("Your family, {additional}.").format(additional=additional),
                    description=_("{author}'s family").format(author=ctx.author.mention)
                    if not marriage
                    else _("Family of {author} and <@{marriage}>").format(
                        author=ctx.author.mention, marriage=marriage
                    ),
                )
                for child in small_list:
                    em.add_field(
                        name=child["name"],
                        value=_("Gender: {gender}, Age: {age}").format(
                            gender=child["gender"], age=child["age"]
                        ),
                        inline=True,
                    )
                em.set_footer(
                    text=_("Page {cur} of {max}").format(
                        cur=children_lists.index(small_list) + 1,
                        max=len(children_lists),
                    )
                )
                embeds.append(em)
            await self.bot.paginator.Paginator(extras=embeds).paginate(ctx)
Exemple #41
0
 def __call__(self, value):
     result = super(DeferredDate, self).__call__(value)
     if result < utcnow().datetime:
         raise ValidateError(_("Date expired"))
     return result
    def show_menu(self, stateInfo):
        info = json.loads(stateInfo)
        videoSource = info["videoSource"]
        hasVideo = info["hasVideo"]
        subtitleFile = info["subtitleFile"]
        subtitleVisible = info["subtitleVisible"]
        isFullscreen = info["isFullscreen"]
        isMiniMode = info["isMiniMode"]
        isOnTop = info["isOnTop"]

        self.menu = Menu(right_click_menu)

        self.menu.getItemById("_fullscreen_quit").isActive = hasVideo
        self.menu.getItemById("_mini_mode").isActive = hasVideo
        self.menu.getItemById("_play_operation_forward").isActive = hasVideo
        self.menu.getItemById("_play_operation_backward").isActive = hasVideo
        self.menu.getItemById("_frame").isActive = hasVideo and not isFullscreen
        self.menu.getItemById("_subtitle_hide").isActive = subtitleFile != ""
        self.menu.getItemById("_subtitle_manual").isActive = hasVideo
        self.menu.getItemById("_subtitle_choose").isActive = subtitleFile != ""
        self.menu.getItemById("_information").isActive = hasVideo

        self.menu.getItemById("_on_top").checked = isOnTop

        self.menu.getItemById("mode_group:radio:in_order").checked = \
            config.playerPlayOrderType == ORDER_TYPE_IN_ORDER
        self.menu.getItemById("mode_group:radio:random").checked = \
            config.playerPlayOrderType == ORDER_TYPE_RANDOM
        self.menu.getItemById("mode_group:radio:single").checked = \
            config.playerPlayOrderType == ORDER_TYPE_SINGLE
        self.menu.getItemById("mode_group:radio:single_cycle").checked = \
            config.playerPlayOrderType == ORDER_TYPE_SINGLE_CYCLE
        self.menu.getItemById("mode_group:radio:playlist_cycle").checked = \
            config.playerPlayOrderType == ORDER_TYPE_PLAYLIST_CYCLE

        self.menu.getItemById("proportion:radio:_p_default").checked = \
            self._proportion == "proportion:radio:_p_default"
        self.menu.getItemById("proportion:radio:_p_4_3").checked = \
            self._proportion == "proportion:radio:_p_4_3"
        self.menu.getItemById("proportion:radio:_p_16_9").checked = \
            self._proportion == "proportion:radio:_p_16_9"
        self.menu.getItemById("proportion:radio:_p_16_10").checked = \
            self._proportion == "proportion:radio:_p_16_10"
        self.menu.getItemById("proportion:radio:_p_1_85_1").checked = \
            self._proportion == "proportion:radio:_p_1_85_1"
        self.menu.getItemById("proportion:radio:_p_2_35_1").checked = \
            self._proportion == "proportion:radio:_p_2_35_1"

        self.menu.getItemById("scale:radio:_s_0_5").checked = \
            self._scale == "scale:radio:_s_0_5"
        self.menu.getItemById("scale:radio:_s_1").checked = \
            self._scale == "scale:radio:_s_1"
        self.menu.getItemById("scale:radio:_s_1_5").checked = \
            self._scale == "scale:radio:_s_1_5"
        self.menu.getItemById("scale:radio:_s_2").checked = \
            self._scale == "scale:radio:_s_2"

        # self.menu.getItemById("_sound_channel").isActive = hasVideo
        # self.menu.getItemById("_sound_channel").setSubMenu(
        #     Menu(sound_channel_sub_menu))
        # self.menu.getItemById("sound_channel:radio:auto").checked = \
        #     self._sound_channel == "sound_channel:radio:auto"
        # self.menu.getItemById("sound_channel:radio:mono").checked = \
        #     self._sound_channel == "sound_channel:radio:mono"
        # self.menu.getItemById("sound_channel:radio:left").checked = \
        #     self._sound_channel == "sound_channel:radio:left"
        # self.menu.getItemById("sound_channel:radio:right").checked = \
        #     self._sound_channel == "sound_channel:radio:right"
        # self.menu.getItemById("sound_channel:radio:stero").checked = \
        #     self._sound_channel == "sound_channel:radio:stero"
        self.menu.getItemById("_sound_muted").checked = config.playerMuted

        self.menu.getItemById("_subtitle_hide").checked = subtitleVisible
        subtitles = get_subtitle_from_movie(videoSource)
        subtitles = _subtitle_menu_items_from_files(subtitles, subtitleFile)
        self.menu.getItemById("_subtitle_choose").setSubMenu(Menu(subtitles))

        self.menu.getItemById("_fullscreen_quit").text = _("Fullscreen") if \
            isFullscreen else _("Exit fullscreen")
        self.menu.getItemById("_mini_mode").text = _("Exit mini mode") if \
            isMiniMode else _("Mini mode")

        self.menu.itemClicked.connect(self._menu_item_invoked)
        self.menu.showRectMenu(QCursor.pos().x(), QCursor.pos().y())
Exemple #43
0
    async def feed(self, ctx):
        _(
            """Feed your pet. This brings up an interactive menu where you can buy a food item.

            Only rangers can use this command."""
        )
        items = [
            (_("Potato"), 10, ":potato:", 1),
            (_("Apple"), 30, ":apple:", 2),
            (_("Cucumber"), 50, ":cucumber:", 4),
            (_("Meat"), 150, ":meat_on_bone:", 10),
            (_("Salad"), 250, ":salad:", 20),
            (_("Sushi"), 800, ":sushi:", 50),
            (_("Adrian's Power Poop"), 2000, ":poop:", 100),
        ]
        item = items[
            await self.bot.paginator.Choose(
                entries=[f"{i[2]} {i[0]} **${i[1]}** -> +{i[3]}" for i in items],
                return_index=True,
                timeout=30,
                title=_("Feed your pet"),
            ).paginate(ctx)
        ]
        if not await has_money(self.bot, ctx.author.id, item[1]):
            return await ctx.send(_("You are too poor to buy this."))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                item[1],
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE pets SET "food"=CASE WHEN "food"+$1>=100 THEN 100 ELSE'
                ' "food"+$1 END WHERE "user"=$2;',
                item[3],
                ctx.author.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=ctx.author.id,
                to=2,
                subject="money",
                data={"Amount": item[1]},
            )
        await ctx.send(
            _(
                "You bought **{item}** for your pet and increased its food bar by"
                " **{points}** points."
            ).format(item=f"{item[2]} {item[0]}", points=item[3])
        )
Exemple #44
0
                try:
                    await ctx.send(
                        file=discord.File(
                            f"assets/classes/{class_.lower().replace(' ', '_')}.png"
                        )
                    )
                except FileNotFoundError:
                    await ctx.send(
                        _(
                            "The image for your class **{class_}** hasn't been added"
                            " yet."
                        ).format(class_=class_)
                    )

    @has_char()
    @commands.command(brief=_("Evolve your class(es)"))
    @locale_doc
    async def evolve(self, ctx):
        _(
            # xgettext: no-python-format
            """Evolve your class, bringing it to the next level and giving better class bonuses.

            You can evolve every 5 levels, i.e. at level 5, level 10, level 15, level 20, level 25 and finally level 30.

            - Warriors gain +1 defense per evolution
            - Thieves gain +8% for their success chance per evolution
            - Mages gain +1 damage per evolution
            - Rangers' pets' hunted item get +3 minimum stat and +6 maximum stat per evolution
              - This means level 1 pets can hunt items from stat 3 to stat 6; level 2 pets from stat 6 to stat 12
            - Raiders gain +0.1 defense and damage raidstats
            - Ritualists gain +5% extra favor when sacrificing per evolution
Exemple #45
0
    async def _class(self, ctx):
        _(
            """Change or select your primary or secondary class.

            - Warriors gain added defense
            - Thieves gain access to `{prefix}steal`
            - Mages gain added damage
            - Rangers gain access to a pet which can hunt for gear items
            - Raiders gain additional raidstats, used in raidbattles and raids
            - Ritualists gain additional favor from sacrificing items and are twice as likely to receive loot from adventures
            (- Paragons gain added damage *and* defense; the class is only available to donators)

            The second class unlocks at level 12. Selecting a class the first time is free (No Class -> Class), but changing it later will cost $5,000 (Class -> another Class)

            (This command has a cooldown of 24 hours)"""
        )
        if int(rpgtools.xptolevel(ctx.character_data["xp"])) >= 12:
            val = await self.bot.paginator.Choose(
                title=_("Select class to change"),
                entries=[_("Primary Class"), _("Secondary Class")],
                return_index=True,
            ).paginate(ctx)
        else:
            val = 0
        embeds = [
            discord.Embed(
                title=_("Warrior"),
                description=_(
                    "The tank class. Charge into battle with additional defense!\n+1"
                    " defense per evolution."
                ),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Thief"),
                description=_(
                    # xgettext: no-python-format
                    "The sneaky money stealer...\nGet access to `{prefix}steal` to"
                    " steal 10% of the target's money, if successful.\n+8% success"
                    " chance per evolution."
                ).format(prefix=ctx.prefix),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Mage"),
                description=_(
                    "Utilise powerful magic for stronger attacks.\n+1 damage per"
                    " evolution."
                ),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Ranger"),
                description=_(
                    "Item hunter and trainer of their very own pet.\nGet access to"
                    " `{prefix}pet` to interact with your pet and let it get items for"
                    " you.\n+3 minimum stat and +6 maximum stat per evolution."
                ).format(prefix=ctx.prefix),
                colour=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Raider"),
                description=_(
                    "A strong warrior who gives their life for the fight against"
                    " Zerekiel.\nEvery evolution boosts your raidstats by an additional"
                    " 10%."
                ),
                colour=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Ritualist"),
                description=_(
                    "A seer, a sacrificer and a follower.\nThe Ritualist devotes their"
                    " life to the god they follow. For every evolution, their"
                    " sacrifices are 5% more effective. They have twice the chance to"
                    " get loot from adventures."
                ),
                colour=self.bot.config.primary_colour,
            ),
        ]
        choices = ["Warrior", "Thief", "Mage", "Ranger", "Raider", "Ritualist"]
        if await user_is_patron(self.bot, ctx.author):
            embeds.append(
                discord.Embed(
                    title=_("Paragon"),
                    description=_(
                        "Absorb the appreciation of the devs into your soul to power"
                        " up.\n+1 damage and defense per evolution."
                    ),
                    color=self.bot.config.primary_colour,
                )
            )
            choices.append("Paragon")
        lines = [
            self.bot.get_class_line(class_) for class_ in ctx.character_data["class"]
        ]
        for line in lines:
            for e in embeds:
                if _(line) == e.title:
                    embeds.remove(e)
            try:
                choices.remove(line)
            except ValueError:
                pass
        profession = await self.bot.paginator.ChoosePaginator(
            extras=embeds, choices=choices
        ).paginate(ctx)
        profession_ = self.bot.config.classes[profession][0]
        new_classes = copy(ctx.character_data["class"])
        new_classes[val] = profession_
        if not await ctx.confirm(
            _(
                "You are about to select the `{profession}` class for yourself."
                " {textaddon} Proceed?"
            ).format(
                textaddon=_(
                    "This **costs nothing**, but changing it later will cost **$5000**."
                )
                if ctx.character_data["class"][val] == "No Class"
                else _("This will cost **$5000**."),
                profession=profession,
            )
        ):
            return await ctx.send(_("Class selection cancelled."))
        if ctx.character_data["class"][val] == "No Class":
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "class"=$1 WHERE "user"=$2;',
                    new_classes,
                    ctx.author.id,
                )
                if profession == "Ranger":
                    await conn.execute(
                        'INSERT INTO pets ("user") VALUES ($1);', ctx.author.id
                    )
            await ctx.send(
                _("Your new class is now `{profession}`.").format(
                    profession=_(profession)
                )
            )
        else:
            if not await self.bot.has_money(ctx.author.id, 5000):
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("You're too poor for a class change, it costs **$5000**.")
                )

            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "class"=$1, "money"="money"-$2 WHERE'
                    ' "user"=$3;',
                    new_classes,
                    5000,
                    ctx.author.id,
                )
                await conn.execute('DELETE FROM pets WHERE "user"=$1;', ctx.author.id)
                if profession == "Ranger":
                    await conn.execute(
                        'INSERT INTO pets ("user") VALUES ($1);', ctx.author.id
                    )
            await self.bot.log_transaction(
                ctx, from_=ctx.author.id, to=2, subject="money", data={"Amount": 5000}
            )
            await ctx.send(
                _(
                    "You selected the class `{profession}`. **$5000** was taken off"
                    " your balance."
                ).format(profession=_(profession))
            )
Exemple #46
0
 async def _on_command_error(self, ctx, error, bypass=False):
     if (hasattr(ctx.command, "on_error") or (ctx.command and hasattr(
             ctx.cog, f"_{ctx.command.cog_name}__error")) and not bypass):
         # Do nothing if the command/cog has its own error handler
         return
     if isinstance(error, commands.CommandNotFound):
         return
     elif isinstance(error, commands.MissingRequiredArgument):
         await ctx.send(
             _("Oops! You forgot a required argument: `{arg}`").format(
                 arg=error.param.name))
     elif isinstance(error, commands.BadArgument):
         if isinstance(error, commands.MessageNotFound):
             await ctx.send(_("The message you referenced was not found."))
         elif isinstance(error, commands.MemberNotFound):
             await ctx.send(_("The member you referenced was not found."))
         elif isinstance(error, commands.GuildNotFound):
             await ctx.send(_("The server you referenced was not found."))
         elif isinstance(error, commands.UserNotFound):
             await ctx.send(_("The user you referenced was not found."))
         elif isinstance(error, commands.ChannelNotFound):
             await ctx.send(_("The channel you referenced was not found."))
         elif isinstance(error, commands.ChannelNotReadable):
             await ctx.send(
                 _("I cannot read messages in the channel you referenced."))
         elif isinstance(error, commands.BadColourArgument):
             await ctx.send(_("I could not parse a colour from this."))
         elif isinstance(error, commands.RoleNotFound):
             await ctx.send(_("The role you referenced was not found."))
         elif isinstance(error, commands.BadInviteArgument):
             await ctx.send(
                 _("The invite you referenced is invalid or has expired."))
         elif isinstance(error, commands.EmojiNotFound):
             await ctx.send(_("The emoji you referenced was not found."))
         elif isinstance(error, commands.BadBoolArgument):
             await ctx.send(_("I could not parse a boolean from this."))
         elif isinstance(error, NotInRange):
             await ctx.send(error.text)
         elif isinstance(error, UserHasNoChar):
             await ctx.send(
                 _("The user you specified as a parameter does not have a"
                   " character."))
         elif isinstance(error, InvalidCrateRarity):
             await ctx.send(
                 _("You did not enter a valid crate rarity. Possible ones are:"
                   " common (c), uncommon (u), rare (r), magic (m), legendary (l) and mystery (myst)."
                   ))
         elif isinstance(error, InvalidCoinSide):
             await ctx.send(
                 _("You did not enter a valid coin side. Please use `heads` or"
                   " `tails`."))
         elif isinstance(error, DateOutOfRange):
             await ctx.send(
                 _("You entered a date that was out of range. It should be newer"
                   " than {date}.").format(date=error.min_))
         elif isinstance(error, InvalidTime):
             await ctx.send(error.text)
         elif isinstance(error, InvalidUrl):
             await ctx.send(
                 _("You sent an invalid URL. Make sure to send the full URL; it"
                   ' should start with "http" and end with ".png" or ".jpeg".'
                   ))
         else:
             await ctx.send(_("You used a malformed argument!"))
     elif isinstance(error, GlobalCooldown):
         return await ctx.send(
             _("You are being rate-limited. Chill down, you can use a command"
               " again in {time}s.").format(
                   time=round(error.retry_after, 2)))
     elif isinstance(error, commands.CommandOnCooldown):
         return await ctx.send(
             _("You are on cooldown. Try again in {time}.").format(
                 time=timedelta(seconds=int(error.retry_after))))
     elif hasattr(error, "original") and isinstance(error.original,
                                                    discord.HTTPException):
         return  # not our fault
     elif isinstance(error, commands.NotOwner):
         await ctx.send(embed=discord.Embed(
             title=_("Permission denied"),
             description=_(
                 ":x: This command is only avaiable for the bot owner."),
             colour=0xFF0000,
         ))
     elif isinstance(error, commands.CheckFailure):
         if isinstance(error, utils.checks.NoCharacter):
             await ctx.send(_("You don't have a character yet."))
         elif isinstance(error, utils.checks.NeedsNoCharacter):
             await ctx.send(
                 _("This command requires you to not have created a character yet."
                   " You already have one."))
         elif isinstance(error, utils.checks.NeedsGod):
             await ctx.send(
                 _("You need to be following a god for this command. Please use"
                   " `{prefix}follow` to choose one.").format(
                       prefix=ctx.prefix))
         elif isinstance(error, utils.checks.NoGuild):
             await ctx.send(
                 _("You need to have a guild to use this command."))
         elif isinstance(error, utils.checks.NeedsNoGuild):
             await ctx.send(
                 _("You need to be in no guild to use this command."))
         elif isinstance(error, utils.checks.NoGuildPermissions):
             await ctx.send(
                 _("Your rank in the guild is too low to use this command.")
             )
         elif isinstance(error, utils.checks.NeedsNoGuildLeader):
             await ctx.send(
                 _("You mustn't be the owner of a guild to use this command."
                   ))
         elif isinstance(error, utils.checks.WrongClass):
             await ctx.send(embed=discord.Embed(
                 title=_("Permission denied"),
                 description=
                 _(":x: You don't have the permissions to use this command. It"
                   " is thought for {error} class users.").format(
                       error=error),
                 colour=0xFF0000,
             ))
         elif isinstance(error, utils.checks.NeedsNoAdventure):
             await ctx.send(
                 _("You are already on an adventure. Use `{prefix}status` to see"
                   " how long it lasts.").format(prefix=ctx.prefix))
         elif isinstance(error, utils.checks.NeedsAdventure):
             await ctx.send(
                 _("You need to be on an adventure to use this command. Try"
                   " `{prefix}adventure`!").format(prefix=ctx.prefix))
         elif isinstance(error, utils.checks.PetGone):
             await ctx.send(
                 _("Your pet has gone missing. Maybe some aliens abducted it?"
                   " Since you can't find it anymore, you are no longer a"
                   " {profession}").format(profession=_("Ranger")))
             classes = ctx.character_data["class"]
             for evolve in get_class_evolves(Ranger):
                 name = evolve.class_name()
                 if name in classes:
                     idx = classes.index(name)
                     break
             classes[idx] = "No Class"
             await self.bot.pool.execute(
                 'UPDATE profile SET "class"=$1 WHERE "user"=$2;',
                 classes,
                 ctx.author.id,
             )
         elif isinstance(error, utils.checks.PetDied):
             await ctx.send(
                 _("Your pet **{pet}** died! You did not give it enough to eat or"
                   " drink. Because of your bad treatment, you are no longer a"
                   " {profession}.").format(pet=ctx.pet_data["name"],
                                            profession=_("Ranger")))
         elif isinstance(error, utils.checks.PetRanAway):
             await ctx.send(
                 _("Your pet **{pet}** ran away! You did not show it your love"
                   " enough! Because of your bad treatment, you are no longer a"
                   " {profession}.").format(pet=ctx.pet_data["name"],
                                            profession=_("Ranger")))
         elif isinstance(error, utils.checks.NoPatron):
             await ctx.send(
                 _("You need to be a {tier} tier donator to use this command."
                   " Please head to `{prefix}donate` and make sure you joined the"
                   " support server if you decide to support us.").format(
                       tier=error.tier.name.title(), prefix=ctx.prefix))
         elif isinstance(error, utils.checks.AlreadyRaiding):
             await ctx.send(
                 _("There is another raid already ongoing. Try again at a later"
                   " time."))
         elif isinstance(error, utils.checks.NoCityOwned):
             await ctx.send(_("Your alliance does not own a city."))
         elif isinstance(error, utils.checks.CityOwned):
             await ctx.send(_("Your alliance already owns a city."))
         elif isinstance(error, utils.checks.NoAlliancePermissions):
             await ctx.send(_("Your alliance rank is too low."))
         elif isinstance(error, utils.checks.NoOpenHelpRequest):
             await ctx.send(
                 _("Your server does not have an open help request."))
         elif isinstance(error, utils.checks.ImgurUploadError):
             await ctx.send(
                 _("There was an error when uploading to Imgur. Please try again"
                   " or visit <https://imgur.com/upload> to manually upload your"
                   " image."))
         else:
             await ctx.send(embed=discord.Embed(
                 title=_("Permission denied"),
                 description=
                 _(":x: You don't have the permissions to use this command. It"
                   " is thought for other users."),
                 colour=0xFF0000,
             ))
     elif isinstance(error, NoChoice):
         await ctx.send(_("You did not choose anything."))
     elif isinstance(error, commands.CommandInvokeError) and hasattr(
             error, "original"):
         if isinstance(
                 error.original,
             (
                 ClientOSError,
                 ServerDisconnectedError,
                 ContentTypeError,
                 TimeoutError,
             ),
         ):
             # Called on 500 HTTP responses
             # TimeoutError: A Discord operation timed out. All others should be handled by us
             return
         elif isinstance(error.original, AsyncpgDataError):
             return await ctx.send(
                 _("An argument or value you entered was far too high for me to"
                   " handle properly!"))
         elif isinstance(error.original, LookupError):
             await ctx.send(
                 _("The languages have been reloaded while you were using a"
                   " command. The execution therefore had to be stopped. Please"
                   " try again."))
         if not self.SENTRY_SUPPORT:
             print(f"In {ctx.command.qualified_name}:", file=sys.stderr)
             traceback.print_tb(error.original.__traceback__)
             print(
                 f"{error.original.__class__.__name__}: {error.original}",
                 file=sys.stderr,
             )
         else:
             try:
                 raise error.original
             except Exception as e:
                 if ctx.guild:
                     guild_id = ctx.guild.id
                 else:
                     guild_id = "None"
                 with sentry_sdk.push_scope() as scope:
                     scope.set_context("message",
                                       {"content": ctx.message.content})
                     scope.set_extra("guild_id", str(guild_id))
                     scope.set_extra("channel_id", str(ctx.channel.id))
                     scope.set_extra("message_id", str(ctx.message.id))
                     scope.set_extra("user_id", str(ctx.author.id))
                     scope.set_tag("command", ctx.command.qualified_name)
                     sentry_sdk.capture_exception(e)
             await ctx.send(
                 _("The command you tried to use ran into an error. The incident"
                   " has been reported and the team will work hard to fix the"
                   " issue!"))
     await ctx.bot.reset_cooldown(ctx)
     if ctx.command.parent:
         if ctx.command.root_parent.name == "guild" and hasattr(
                 ctx, "character_data"):
             await self.bot.reset_guild_cooldown(ctx)
         elif ctx.command.root_parent.name == "alliance":
             await self.bot.reset_alliance_cooldown(ctx)
Exemple #47
0
    async def create(self, ctx, *, name: str = None):
        _("""`[name]` - The name to give your character; will be interactive if not given

            Create a new character and start playing IdleRPG.

            By creating a character, you agree to the [bot rules](https://wiki.idlerpg.xyz/index.php?title=Rules#botrules).
            No idea where to go from here? Check out our [tutorial](https://idlerpg.xyz/tutorial/).
            If you still have questions afterward, feel free to ask us on the official [support server](https://support.idlerpg.xyz/).

            (This command has a cooldown of 1 hour.)""")
        if not name:
            await ctx.send(
                _("""\
What shall your character's name be? (Minimum 3 Characters, Maximum 20)

**Please note that with the creation of a character, you agree to these rules:**
1) Only up to two characters per individual
2) No abusing or benefiting from bugs or exploits
3) Be friendly and kind to other players
4) Trading in-game items or currency for real money or items directly comparable to currency is forbidden

IdleRPG is a global bot, your characters are valid everywhere"""))

            def mycheck(amsg):
                return amsg.author == ctx.author and amsg.channel == ctx.channel

            try:
                name = await self.bot.wait_for("message",
                                               timeout=60,
                                               check=mycheck)
            except asyncio.TimeoutError:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(_("Timeout expired. Please retry!"))
            name = name.content
        else:
            if not await ctx.confirm(
                    _("""\
**Please note that with the creation of a character, you agree to these rules:**
1) Only up to two characters per individual
2) No abusing or benefiting from bugs or exploits
3) Be friendly and kind to other players
4) Trading in-game items or currency for real money or items directly comparable to currency is forbidden

IdleRPG is a global bot, your characters are valid everywhere""")):
                return await ctx.send(
                    _("Creation of your character cancelled."))
        if len(name) > 2 and len(name) < 21:
            if "`" in name:
                return await ctx.send(
                    _("Illegal character (`) found in the name. Please try again and"
                      " choose another name."))

            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    "INSERT INTO profile VALUES ($1, $2, $3, $4);",
                    ctx.author.id,
                    name,
                    100,
                    0,
                )
                await self.bot.create_item(
                    name=_("Starter Sword"),
                    value=0,
                    type_="Sword",
                    damage=3.0,
                    armor=0.0,
                    owner=ctx.author,
                    hand="any",
                    equipped=True,
                    conn=conn,
                )
                await self.bot.create_item(
                    name=_("Starter Shield"),
                    value=0,
                    type_="Shield",
                    damage=0.0,
                    armor=3.0,
                    owner=ctx.author,
                    hand="left",
                    equipped=True,
                    conn=conn,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=1,
                    to=ctx.author.id,
                    subject="money",
                    data={"Amount": 100},
                    conn=conn,
                )
            await ctx.send(
                _("Successfully added your character **{name}**! Now use"
                  " `{prefix}profile` to view your character!").format(
                      name=name, prefix=ctx.prefix))
        elif len(name) < 3 or len(name) > 20:
            await ctx.send(
                _("Character names must be at least 3 characters and up to 20."
                  ))
            await self.bot.reset_cooldown(ctx)
Exemple #48
0
class Marriage(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        with open("assets/data/boynames.txt") as boy_names:
            self.boynames = boy_names.readlines()
        with open("assets/data/girlnames.txt") as girl_names:
            self.girlnames = girl_names.readlines()

    def get_max_kids(self, lovescore):
        max_, missing = divmod(lovescore, 250_000)
        return 10 + max_, 250_000 - missing

    @has_char()
    @commands.guild_only()
    @commands.command(aliases=["marry"], brief=_("Propose to a player"))
    @locale_doc
    async def propose(self, ctx, partner: MemberWithCharacter):
        _(
            """`<partner>` - A discord User with a character who is not yet married

            Propose to a player for marriage. Once they accept, you are married.

            When married, your partner will get bonuses from your adventures, you can have children, which can do different things (see `{prefix}help familyevent`) and increase your lovescore, which has an effect on the [adventure bonus](https://wiki.idlerpg.xyz/index.php?title=Family#Adventure_Bonus).
            If any of you has children, they will be brought together to one family.

            Only players who are not already married can use this command."""
        )
        if partner == ctx.author:
            return await ctx.send(
                _("You should have a better friend than only yourself.")
            )
        if ctx.character_data["marriage"] != 0 or ctx.user_data["marriage"] != 0:
            return await ctx.send(_("One of you is married."))
        msg = await ctx.send(
            embed=discord.Embed(
                title=_("{author} has proposed for a marriage!").format(
                    author=ctx.disp,
                ),
                description=_(
                    "{author} wants to marry you, {partner}! React with :heart: to"
                    " marry them!"
                ).format(author=ctx.author.mention, partner=partner.mention),
                colour=0xFF0000,
            )
            .set_image(url=ctx.author.avatar_url)
            .set_thumbnail(
                url="http://www.maasbach.com/wp-content/uploads/The-heart.png"
            )
        )
        await msg.add_reaction("\U00002764")

        def reactioncheck(reaction, user):
            return (
                str(reaction.emoji) == "\U00002764"
                and reaction.message.id == msg.id
                and user.id == partner.id
            )

        try:
            _reaction, _user = await self.bot.wait_for(
                "reaction_add", timeout=120.0, check=reactioncheck
            )
        except asyncio.TimeoutError:
            return await ctx.send(_("They didn't want to marry."))
        # check if someone married in the meantime
        check1 = await self.bot.cache.get_profile_col(ctx.author.id, "marriage")
        check2 = await self.bot.cache.get_profile_col(partner.id, "marriage")
        if check1 or check2:
            return await ctx.send(
                _("Either you or your lovee married in the meantime... :broken_heart:")
            )
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "marriage"=$1 WHERE "user"=$2;',
                partner.id,
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE profile SET "marriage"=$1 WHERE "user"=$2;',
                ctx.author.id,
                partner.id,
            )
            await conn.execute(
                'UPDATE children SET "father"=$1 WHERE "father"=0 AND "mother"=$2;',
                partner.id,
                ctx.author.id,
            )
            await conn.execute(
                'UPDATE children SET "father"=$1 WHERE "father"=0 AND "mother"=$2;',
                ctx.author.id,
                partner.id,
            )
        await self.bot.cache.update_profile_cols_abs(ctx.author.id, marriage=partner.id)
        await self.bot.cache.update_profile_cols_abs(partner.id, marriage=ctx.author.id)
        # we give familyevent cooldown to the new partner to avoid exploitation
        await self.bot.set_cooldown(partner.id, 1800, "familyevent")
        await ctx.send(
            _("Aww! :heart: {author} and {partner} are now married!").format(
                author=ctx.author.mention, partner=partner.mention
            )
        )

    @has_char()
    @commands.command(brief=_("Break up with your partner"))
    @locale_doc
    async def divorce(self, ctx):
        _(
            """Divorce your partner, effectively un-marrying them.

            When divorcing, any kids you have will be split between you and your partner. Each partner will get the children born with their `{prefix}child` commands.
            You can marry another person right away, if you so choose. Divorcing has no negative consequences on gameplay.

            Only married players can use this command."""
        )
        if not ctx.character_data["marriage"]:
            return await ctx.send(_("You are not married yet."))
        if not await ctx.confirm(
            _(
                "Are you sure you want to divorce your partner? Some of your children"
                " may be given to your partner."
            )
        ):
            return await ctx.send(
                _("Cancelled the divorce. I guess the marriage is safe for now?")
            )
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "marriage"=0 WHERE "user"=$1;', ctx.author.id
            )
            await conn.execute(
                'UPDATE profile SET "marriage"=0 WHERE "user"=$1;',
                ctx.character_data["marriage"],
            )
            await conn.execute(
                'UPDATE children SET "father"=0 WHERE "mother"=$1;', ctx.author.id
            )
            await conn.execute(
                'UPDATE children SET "father"=0 WHERE "mother"=$1;',
                ctx.character_data["marriage"],
            )
        await self.bot.cache.update_profile_cols_abs(ctx.author.id, marriage=0)
        await self.bot.cache.update_profile_cols_abs(
            ctx.character_data["marriage"], marriage=0
        )
        await ctx.send(_("You are now divorced."))

    @has_char()
    @commands.command(brief=_("Show your partner"))
    @locale_doc
    async def relationship(self, ctx):
        _(
            """Show your partner's Discord Tag. This works fine across server.

            Only married players can use this command."""
        )
        if not ctx.character_data["marriage"]:
            return await ctx.send(_("You are not married yet."))
        partner = await rpgtools.lookup(self.bot, ctx.character_data["marriage"])
        await ctx.send(
            _("You are currently married to **{partner}**.").format(partner=partner)
        )

    @has_char()
    @commands.command(brief=_("Show a player's lovescore"))
    @locale_doc
    async def lovescore(self, ctx, user: UserWithCharacter = Author):
        _(
            """`[user]` - The user whose lovescore to show; defaults to oneself

            Show the lovescore a player has. Lovescore can be increased by their partner spoiling them or going on dates.

            Lovescore affects the [adventure bonus](https://wiki.idlerpg.xyz/index.php?title=Family#Adventure_Bonus) and the amount of children you can have."""
        )
        data = ctx.character_data if user == ctx.author else ctx.user_data
        if data["marriage"]:
            partner = await rpgtools.lookup(self.bot, data["marriage"])
        else:
            partner = _("noone")
        await ctx.send(
            _(
                "{user}'s overall love score is **{score}**. {user} is married to"
                " **{partner}**."
            ).format(user=user.name, score=data["lovescore"], partner=partner)
        )

    @has_char()
    @commands.command(brief=_("Increase your partner's lovescore"))
    @locale_doc
    async def spoil(self, ctx, item: IntFromTo(1, 40) = None):
        _(
            """`[item]` - The item to buy, a whole number from 1 to 40; if not given, displays the list of items

            Buy something for your partner to increase *their* lovescore. To increase your own lovescore, your partner should spoil you.

            Please note that these items are not usable and do not have an effect on gameplay, beside increasing lovescore.

            Only players who are married can use this command."""
        )
        items = [
            (_("Dog :dog2:"), 50),
            (_("Cat :cat2:"), 50),
            (_("Cow :cow2:"), 75),
            (_("Penguin :penguin:"), 100),
            (_("Unicorn :unicorn:"), 1000),
            (_("Potato :potato:"), 1),
            (_("Sweet potato :sweet_potato:"), 2),
            (_("Peach :peach:"), 5),
            (_("Ice Cream :ice_cream:"), 10),
            (_("Bento Box :bento:"), 50),
            (_("Movie Night :ticket:"), 75),
            (_("Video Game Night :video_game:"), 10),
            (_("Camping Night :fishing_pole_and_fish:"), 15),
            (_("Couple Competition :trophy:"), 30),
            (_("Concert Night :musical_keyboard:"), 100),
            (_("Bicycle :bike:"), 100),
            (_("Motorcycle :motorcycle:"), 250),
            (_("Car :red_car:"), 300),
            (_("Private Jet :airplane:"), 1000),
            (_("Space Rocket :rocket:"), 10000),
            (_("Credit Card :credit_card:"), 20),
            (_("Watch :watch:"), 100),
            (_("Phone :iphone:"), 100),
            (_("Bed :bed:"), 500),
            (_("Home films :projector:"), 750),
            (_("Satchel :school_satchel:"), 25),
            (_("Purse :purse:"), 30),
            (_("Shoes :athletic_shoe:"), 150),
            (_("Casual Attire :shirt:"), 200),
            (_("Ring :ring:"), 1000),
            (_("Balloon :balloon:"), 10),
            (_("Flower Bouquet :bouquet:"), 25),
            (_("Expensive Chocolates :chocolate_bar:"), 40),
            (_("Declaration of Love :love_letter:"), 50),
            (_("Key to Heart :key2:"), 100),
            (_("Ancient Vase :amphora:"), 15000),
            (_("House :house:"), 25000),
            (_("Super Computer :computer:"), 50000),
            (_("Precious Gemstone Collection :gem:"), 75000),
            (_("Planet :earth_americas:"), 1_000_000),
        ]
        text = _("Price")
        items_str = "\n".join(
            [
                f"{idx + 1}.) {item} ... {text}: **${price}**"
                for idx, (item, price) in enumerate(items)
            ]
        )
        if not item:
            text = _(
                "To buy one of these items for your partner, use `{prefix}spoil shopid`"
            ).format(prefix=ctx.prefix)
            return await ctx.send(f"{items_str}\n\n{text}")
        item = items[item - 1]
        if ctx.character_data["money"] < item[1]:
            return await ctx.send(_("You are too poor to buy this."))
        if not ctx.character_data["marriage"]:
            return await ctx.send(_("You're not married yet."))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "lovescore"="lovescore"+$1 WHERE "user"=$2;',
                item[1],
                ctx.character_data["marriage"],
            )
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                item[1],
                ctx.author.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=ctx.author.id,
                to=2,
                subject="money",
                data={"Amount": item[1]},
                conn=conn,
            )
        await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=-item[1])
        await self.bot.cache.update_profile_cols_rel(
            ctx.character_data["marriage"], lovescore=item[1]
        )
        await ctx.send(
            _(
                "You bought a **{item}** for your partner and increased their love"
                " score by **{points}** points!"
            ).format(item=item[0], points=item[1])
        )
        user = await self.bot.get_user_global(ctx.character_data["marriage"])
        if not user:
            return await ctx.send(
                _("Failed to DM your spouse, could not find their Discord account")
            )
        await user.send(
            "**{author}** bought you a **{item}** and increased your love score by"
            " **{points}** points!".format(
                author=ctx.author, item=item[0], points=item[1]
            )
        )

    @has_char()
    @commands.command(brief=_("Take your partner on a date"))
    @locale_doc
    @user_cooldown(43200)
    async def date(self, ctx):
        _(
            """Take your partner on a date to increase *their* lovescore. To increase your own lovescore, your partner should go on a date with you.

            The lovescore gained from dates can range from 10 to 150 in steps of 10.

            Only players who are married can use this command.
            (This command has a cooldown of 12 hours.)"""
        )
        num = random.randint(1, 15) * 10
        marriage = ctx.character_data["marriage"]
        if not marriage:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("You are not married yet."))
        await self.bot.pool.execute(
            'UPDATE profile SET "lovescore"="lovescore"+$1 WHERE "user"=$2;',
            num,
            marriage,
        )
        await self.bot.cache.update_profile_cols_rel(marriage, lovescore=num)

        partner = await self.bot.get_user_global(marriage)
        scenario = random.choice(
            [
                _("You and {partner} went on a nice candlelit dinner."),
                _("You and {partner} had stargazed all night."),
                _("You and {partner} went to a circus that was in town."),
                _("You and {partner} went out to see a romantic movie."),
                _("You and {partner} went out to get ice cream."),
                _("You and {partner} had an anime marathon."),
                _("You and {partner} went for a spontaneous hiking trip."),
                _("You and {partner} decided to visit Paris."),
                _("You and {partner} went ice skating together."),
            ]
        ).format(partner=(partner.mention if partner else _("Unknown User")))
        text = _("This increased their lovescore by {num}").format(num=num)
        await ctx.send(f"{scenario} {text}")

    async def get_random_name(self, gender, avoid):
        if gender == "f":
            data = self.girlnames
        else:
            data = self.boynames
        name = random.choice(data).strip("\n")
        while name in avoid:
            name = random.choice(data)  # avoid duplicate names
        return name

    async def lovescore_up(self, ctx, marriage, max_, missing, toomany):
        additional = (
            ""
            if not toomany
            else _(
                "You already have {max_} children. You can increase this limit"
                " by increasing your lovescores to get {amount} more."
            ).format(max_=max_, amount=f"{missing:,}")
        )
        ls = random.randint(10, 50)
        await self.bot.pool.execute(
            'UPDATE profile SET "lovescore"="lovescore"+$1 WHERE "user"=$2 OR'
            ' "user"=$3;',
            ls,
            ctx.author.id,
            marriage,
        )
        await self.bot.cache.update_profile_cols_rel(marriage, lovescore=ls)
        await self.bot.cache.update_profile_cols_rel(ctx.author.id, lovescore=ls)
        return await ctx.send(
            _(
                "You had a lovely night and gained {ls} lovescore. 😏\n\n{additional}".format(
                    ls=ls, additional=additional
                )
            )
        )

    @has_char()
    @commands.guild_only()
    @user_cooldown(3600)
    @commands.command(
        aliases=["f**k", "sex", "breed"], brief=_("Have a child with your partner")
    )
    @locale_doc
    async def child(self, ctx):
        _(
            # xgettext: no-python-format
            """Have a child with your partner.

            Children on their own don't do much, but `{prefix}familyevent` can effect your money and crates.
            To have a child, your partner has to be on the server to accept the checkbox.

            There is a 50% chance that you will have a child, and a 50% chance to just *have fun* (if you know what I'm saying) and gain between 10 and 50 lovescore.
            When you have a child, there is a 50% chance for it to be a boy and a 50% chance to be a girl.

            Your partner and you can enter a name for your child once the bot prompts you to. (Do not include `{prefix}`)
            If you fail to choose a name in time, the bot will choose one for you from about 500 pre-picked ones.

            For identification purposes, you cannot have two children with the same name in your family, so make sure to pick a unique one.

            Only players who are married can use this command.
            (This command has a cooldown of 1 hour.)"""
        )
        marriage = ctx.character_data["marriage"]
        if not marriage:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("Can't produce a child alone, can you?"))
        async with self.bot.pool.acquire() as conn:
            names = await conn.fetch(
                'SELECT name FROM children WHERE "mother"=$1 OR "father"=$1;',
                ctx.author.id,
            )
            spouse = await self.bot.cache.get_profile_col(
                marriage, "lovescore", conn=conn
            )
        max_, missing = self.get_max_kids(ctx.character_data["lovescore"] + spouse)
        names = [name["name"] for name in names]
        user = await self.bot.get_user_global(marriage)
        if not await ctx.confirm(
            _("{user}, do you want to make a child with {author}?").format(
                user=user.mention, author=ctx.author.mention
            ),
            user=user,
        ):
            return await ctx.send(_("O.o not in the mood today?"))

        if len(names) >= max_:
            return await self.lovescore_up(ctx, marriage, max_, missing, True)

        if random.choice([True, False]):
            return await self.lovescore_up(ctx, marriage, max_, missing, False)
        gender = random.choice(["m", "f"])
        if gender == "m":
            await ctx.send(
                _(
                    "It's a boy! Your night of love was successful! Please enter a name"
                    " for your child."
                )
            )
        elif gender == "f":
            await ctx.send(
                _(
                    "It's a girl! Your night of love was successful! Please enter a"
                    " name for your child."
                )
            )

        def check(msg):
            return (
                msg.author.id in [ctx.author.id, marriage]
                and 1 <= len(msg.content) <= 20
                and msg.channel.id == ctx.channel.id
            )

        name = None
        while not name:
            try:
                msg = await self.bot.wait_for("message", check=check, timeout=30)
                name = msg.content.replace("@", "@\u200b")
            except asyncio.TimeoutError:
                name = await self.get_random_name(gender, names)
                await ctx.send(
                    _("You didn't enter a name, so we chose {name} for you.").format(
                        name=name
                    )
                )
                break
            if name in names:
                await ctx.send(
                    _(
                        "One of your children already has that name, please choose"
                        " another one."
                    )
                )
                name = None
        await self.bot.pool.execute(
            'INSERT INTO children ("mother", "father", "name", "age", "gender")'
            " VALUES ($1, $2, $3, $4, $5);",
            ctx.author.id,
            marriage,
            name,
            0,
            gender,
        )
        await ctx.send(_("{name} was born.").format(name=name))

    @has_char()
    @commands.command(brief=_("View your children"))
    @locale_doc
    async def family(self, ctx):
        _("""View your children. This will display their name, age and gender.""")
        marriage = ctx.character_data["marriage"]
        children = await self.bot.pool.fetch(
            'SELECT * FROM children WHERE ("mother"=$1 AND "father"=$2) OR ("father"=$1'
            ' AND "mother"=$2);',
            ctx.author.id,
            marriage,
        )

        additional = (
            _("{amount} children").format(amount=len(children))
            if len(children) != 1
            else _("one child")
        )
        em = discord.Embed(
            title=_("Your family, {additional}.").format(additional=additional),
            description=_("{author}'s family").format(author=ctx.author.mention)
            if not marriage
            else _("Family of {author} and <@{marriage}>").format(
                author=ctx.author.mention, marriage=marriage
            ),
        )
        if not children:
            em.add_field(
                name=_("No children yet"),
                value=_("Use `{prefix}child` to make one!").format(prefix=ctx.prefix)
                if marriage
                else _(
                    "Get yourself a partner and use `{prefix}child` to make one!"
                ).format(prefix=ctx.prefix),
            )
        if len(children) <= 5:
            for child in children:
                em.add_field(
                    name=child["name"],
                    value=_("Gender: {gender}, Age: {age}").format(
                        gender=child["gender"], age=child["age"]
                    ),
                    inline=False,
                )
            em.set_thumbnail(url=ctx.author.avatar_url)
            await ctx.send(embed=em)
        else:
            embeds = []
            children_lists = list(chunks(children, 9))
            for small_list in children_lists:
                em = discord.Embed(
                    title=_("Your family, {additional}.").format(additional=additional),
                    description=_("{author}'s family").format(author=ctx.author.mention)
                    if not marriage
                    else _("Family of {author} and <@{marriage}>").format(
                        author=ctx.author.mention, marriage=marriage
                    ),
                )
                for child in small_list:
                    em.add_field(
                        name=child["name"],
                        value=_("Gender: {gender}, Age: {age}").format(
                            gender=child["gender"], age=child["age"]
                        ),
                        inline=True,
                    )
                em.set_footer(
                    text=_("Page {cur} of {max}").format(
                        cur=children_lists.index(small_list) + 1,
                        max=len(children_lists),
                    )
                )
                embeds.append(em)
            await self.bot.paginator.Paginator(extras=embeds).paginate(ctx)

    @has_char()
    @user_cooldown(1800)
    @commands.command(aliases=["fe"], brief=_("Events happening to your family"))
    @locale_doc
    async def familyevent(self, ctx):
        _(
            """Allow your children to do something, this includes a multitude of events.

            Every time you or your partner uses this command, your children:
              - have an 8/23 chance to grow older by one year
              - have a 4/23 chance to be renamed
              - have a 4/23 chance to take up to 1/64th of your money
              - have a 4/23 chance to give you up to 1/64th of your current money extra
              - have a 2/23 chance to find a random crate for you:
                + 500/761 (65%) chance for a common crate
                + 200/761 (26%) chance for an uncommon crate
                + 50/761 (6%) chance for a rare crate
                + 10/761 (1%) chance for a magic crate
                + 1/761 (0.1%) chance for a legendary crate
              - have a 1/23 chance to die

            In each event you will know what happened.

            Only players who are married and have children can use this command.
            (This command has a cooldown of 30 minutes.)"""
        )
        children = await self.bot.pool.fetch(
            'SELECT * FROM children WHERE ("mother"=$1 AND "father"=$2) OR ("father"=$1'
            ' AND "mother"=$2);',
            ctx.author.id,
            ctx.character_data["marriage"],
        )
        if not children:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("You don't have kids yet."))
        target = random.choice(children)
        event = random.choice(
            ["death"]
            + ["age"] * 8
            + ["namechange"] * 4
            + ["crate"] * 2
            + ["moneylose"] * 4
            + ["moneygain"] * 4
        )
        if event == "death":
            cause = random.choice(
                [
                    _("They died because of a shampoo overdose!"),
                    _("They died of lovesickness..."),
                    _("They've died of age."),
                    _("They died of loneliness."),
                    _("A horde of goblins got them."),
                    _(
                        "They have finally decided to move out after all these years,"
                        " but couldn't survive a second alone."
                    ),
                    _("Spontaneous combustion removed them from existence."),
                    _("While exploring the forest, they have gotten lost."),
                    _("They've left through a portal into another dimension..."),
                    _(
                        "The unbearable pain of stepping on a Lego\© brick killed them."  # noqa
                    ),
                    _("You heard a landmine going off nearby..."),
                    _("They have been abducted by aliens!"),
                    _("The Catholic Church got them..."),
                    _("They starved after becoming a communist."),
                ]
            )
            await self.bot.pool.execute(
                'DELETE FROM children WHERE "name"=$1 AND (("mother"=$2 AND'
                ' "father"=$4) OR ("father"=$2 AND "mother"=$4)) AND "age"=$3;',
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{name} died at the age of {age}! {cause}").format(
                    name=target["name"], age=target["age"], cause=cause
                )
            )
        elif event == "moneylose":
            cause = random.choice(
                [
                    _(
                        "fell in love with a woman on the internet, but the woman was a"
                        " man and stole their money."
                    ),
                    _("has been arrested and had to post bail."),
                    _("bought fortnite skins with your credit card."),
                    _("decided to become communist and gave the money to others."),
                    _("was caught pickpocketing and you had to pay the fine."),
                    _("gave it to a beggar."),
                    _("borrowed it to attend the local knights course."),
                    _("spent it in the shop."),
                    _("bought some toys."),
                    _("has gambling addiction and lost the money..."),
                ]
            )
            money = random.randint(0, int(ctx.character_data["money"] / 64))
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                    money,
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=ctx.author.id,
                    to=2,
                    subject="money",
                    data={"Amount": -money},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=-money)

            return await ctx.send(
                _("You lost ${money} because {name} {cause}").format(
                    money=money, name=target["name"], cause=cause
                )
            )
        elif event == "moneygain":
            cause = random.choice(
                [
                    _("finally found a job!"),
                    _("won a lottery."),
                    _("sold their toys."),
                    _("got money from another kid that decided to become communist."),
                    _("stole it from a traveller."),
                    _("finished a quest with a money reward."),
                    _("used dark magic to summon some money."),
                    _("looted a local warehouse and sold the wares."),
                    _("solved an enigma with a money reward."),
                ]
            )
            money = random.randint(0, int(ctx.character_data["money"] / 64))
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                    money,
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=1,
                    to=ctx.author.id,
                    subject="money",
                    data={"Amount": money},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(ctx.author.id, money=money)
            return await ctx.send(
                _("{name} gave you ${money}, they {cause}").format(
                    name=target["name"], money=money, cause=cause
                )
            )
        elif event == "crate":
            type_ = random.choice(
                ["common"] * 500
                + ["uncommon"] * 200
                + ["rare"] * 50
                + ["magic"] * 10
                + ["legendary"]
            )
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    f'UPDATE profile SET "crates_{type_}"="crates_{type_}"+1 WHERE'
                    ' "user"=$1;',
                    ctx.author.id,
                )
                await self.bot.log_transaction(
                    ctx,
                    from_=ctx.author.id,
                    to=2,
                    subject="crates",
                    data={"Rarity": type_, "Amount": 1},
                    conn=conn,
                )
            await self.bot.cache.update_profile_cols_rel(
                ctx.author.id, **{f"crates_{type_}": 1}
            )
            emoji = getattr(self.bot.cogs["Crates"].emotes, type_)
            return await ctx.send(
                _("{name} found a {emoji} {type_} crate for you!").format(
                    name=target["name"], emoji=emoji, type_=type_
                )
            )
        elif event == "age":
            await self.bot.pool.execute(
                'UPDATE children SET "age"="age"+1 WHERE "name"=$1 AND (("mother"=$2'
                ' AND "father"=$4) OR ("father"=$2 AND "mother"=$4)) AND "age"=$3;',
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{name} is now {age} years old.").format(
                    name=target["name"], age=target["age"] + 1
                )
            )
        elif event == "namechange":
            names = [c["name"] for c in children]
            names.remove(target["name"])

            def check(msg):
                return (
                    msg.author.id in [ctx.author.id, ctx.character_data["marriage"]]
                    and msg.channel.id == ctx.channel.id
                )

            name = None
            while not name:
                await ctx.send(
                    _(
                        "{name} can be renamed! Within 30 seconds, enter a new"
                        " name:\nType `cancel` to leave the name unchanged."
                    ).format(name=target["name"])
                )
                try:
                    msg = await self.bot.wait_for("message", check=check, timeout=30)
                    name = msg.content.replace("@", "@\u200b")
                except asyncio.TimeoutError:
                    return await ctx.send(_("You didn't enter a name."))
                if name.lower() == "cancel":
                    return await ctx.send(_("You didn't want to rename."))
                if len(name) == 0 or len(name) > 20:
                    await ctx.send(_("Name must be 1 to 20 characters only."))
                    name = None
                    continue
                if name in names:
                    await ctx.send(
                        _(
                            "One of your children already has that name, please choose"
                            " another one."
                        )
                    )
                    name = None
                    continue
                try:
                    if not await ctx.confirm(
                        _(
                            '{author} Are you sure you want to rename "{old_name}" to'
                            ' "{new_name}"?'
                        ).format(
                            author=ctx.author.mention,
                            old_name=target["name"],
                            new_name=name,
                        )
                    ):
                        await ctx.send(
                            _('You didn\'t change the name to "{new_name}".').format(
                                new_name=name
                            )
                        )
                        name = None
                        await self.bot.set_cooldown(ctx, 1800)
                except self.bot.paginator.NoChoice:
                    await ctx.send(_("You didn't confirm."))
                    name = None

            if name == target["name"]:
                return await ctx.send(_("You didn't change their name."))
            await self.bot.pool.execute(
                'UPDATE children SET "name"=$1 WHERE "name"=$2 AND (("mother"=$3 AND'
                ' "father"=$5) OR ("father"=$3 AND "mother"=$5)) AND "age"=$4;',
                name,
                target["name"],
                ctx.author.id,
                target["age"],
                ctx.character_data["marriage"],
            )
            return await ctx.send(
                _("{old_name} is now called {new_name}.").format(
                    old_name=target["name"], new_name=name
                )
            )
Exemple #49
0
 def __call__(self, value):
     value = str(value)
     length = len(value)
     if length > self.max_length or length < self.min_length:
         raise ValidateError(_(u"string length must be between {} and {}"), self.min_length, self.max_length)
     return value
Exemple #50
0
    async def equip(self, ctx, itemid: int):
        _("""`<itemid>` - The ID of the item to equip

            Equip an item by its ID, you can find the item IDs in your inventory.

            Each item has an assigned hand slot,
              "any" meaning that the item can go in either hand,
              "both" meaning it takes both hands,
              "left" and "right" should be clear.

            You cannot equip two items that use the same hand, or a second item if the one your have equipped is two-handed."""
          )
        async with self.bot.pool.acquire() as conn:
            item = await conn.fetchrow(
                'SELECT ai.* FROM inventory i JOIN allitems ai ON (i."item"=ai."id")'
                ' WHERE ai."owner"=$1 and ai."id"=$2;',
                ctx.author.id,
                itemid,
            )
            if not item:
                return await ctx.send(
                    _("You don't own an item with the ID `{itemid}`.").format(
                        itemid=itemid))
            olditems = await conn.fetch(
                "SELECT ai.* FROM profile p JOIN allitems ai ON (p.user=ai.owner) JOIN"
                " inventory i ON (ai.id=i.item) WHERE i.equipped IS TRUE AND"
                " p.user=$1;",
                ctx.author.id,
            )
            put_off = []
            if olditems:
                num_any = sum(1 for i in olditems if i["hand"] == "any")
                if len(olditems) == 1 and olditems[0]["hand"] == "both":
                    await conn.execute(
                        'UPDATE inventory SET "equipped"=False WHERE "item"=$1;',
                        olditems[0]["id"],
                    )
                    put_off = [olditems[0]["id"]]
                elif item["hand"] == "both":
                    all_ids = [i["id"] for i in olditems]
                    await conn.execute(
                        'UPDATE inventory SET "equipped"=False WHERE "item"=ANY($1);',
                        all_ids,
                    )
                    put_off = all_ids
                else:
                    if len(olditems) < 2:
                        if (item["hand"] != "any"
                                and olditems[0]["hand"] == item["hand"]):
                            await conn.execute(
                                'UPDATE inventory SET "equipped"=False WHERE'
                                ' "item"=$1;',
                                olditems[0]["id"],
                            )
                            put_off = [olditems[0]["id"]]
                    elif (item["hand"] == "left"
                          or item["hand"] == "right") and num_any < 2:
                        item_to_remove = [
                            i for i in olditems if i["hand"] == item["hand"]
                        ]
                        if not item_to_remove:
                            item_to_remove = [
                                i for i in olditems if i["hand"] == "any"
                            ]
                        item_to_remove = item_to_remove[0]["id"]
                        await conn.execute(
                            'UPDATE inventory SET "equipped"=False WHERE "item"=$1;',
                            item_to_remove,
                        )
                        put_off = [item_to_remove]
                    else:
                        item_to_remove = await self.bot.paginator.Choose(
                            title=_("Select an item to unequip"),
                            footer=
                            _("Hit the button with the item you wish to remove"
                              ),
                            return_index=True,
                            entries=[
                                f"{i['name']}, {i['type']}, {i['damage'] + i['armor']}"
                                for i in olditems
                            ],
                        ).paginate(ctx)
                        item_to_remove = olditems[item_to_remove]["id"]
                        await conn.execute(
                            'UPDATE inventory SET "equipped"=False WHERE "item"=$1;',
                            item_to_remove,
                        )
                        put_off = [item_to_remove]
            await conn.execute(
                'UPDATE inventory SET "equipped"=True WHERE "item"=$1;',
                itemid)
        await self.bot.reset_cooldown(ctx)
        if put_off:
            await ctx.send(
                _("Successfully equipped item `{itemid}` and put off item(s)"
                  " {olditems}.").format(olditems=", ".join(f"`{i}`"
                                                            for i in put_off),
                                         itemid=item["id"]))
        else:
            await ctx.send(
                _("Successfully equipped item `{itemid}`.").format(
                    itemid=itemid))
Exemple #51
0
 def __call__(self, value):
     value = super().__call__(value)
     if value < 0:
         raise ValidateError(_(u"{} should be positive integer"), value)
     return value
Exemple #52
0
    async def merge(self, ctx, firstitemid: int, seconditemid: int):
        _("""`<firstitemid>` - The ID of the first item
            `<seconditemid>` - The ID of the second item

            Merges two items to a better one.

            ⚠ The first item will be upgraded by +1, the second item will be destroyed.

            The two items must be of the same item type and within a 5 stat range of each other.
            For example, if the first item is a 23 damage Scythe, the second item must be a Scythe with damage 18 to 28.

            One handed weapons can be merged up to 41, two handed items up to 82

            (This command has a cooldown of 1 hour.)""")
        if firstitemid == seconditemid:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("Good luck with that."))
        async with self.bot.pool.acquire() as conn:
            item = await conn.fetchrow(
                'SELECT * FROM allitems WHERE "id"=$1 AND "owner"=$2;',
                firstitemid,
                ctx.author.id,
            )
            item2 = await conn.fetchrow(
                'SELECT * FROM allitems WHERE "id"=$1 AND "owner"=$2;',
                seconditemid,
                ctx.author.id,
            )
            if not item or not item2:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(_("You don't own both of these items."))
            if item["type"] != item2["type"]:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("The items are of unequal type. You may only merge a sword with"
                      " a sword or a shield with a shield."))
            stat = "damage" if item["type"] != "Shield" else "armor"
            min_ = item[stat] - 5
            main = item[stat]
            main2 = item2[stat]
            max_ = item[stat] + 5
            main_hand = item["hand"]
            if (main > 40
                    and main_hand != "both") or (main > 81
                                                 and main_hand == "both"):
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("This item is already on the maximum upgrade level."))
            if not min_ <= main2 <= max_:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("The second item's stat must be in the range of `{min_}` to"
                      " `{max_}` to upgrade an item with the stat of `{stat}`."
                      ).format(min_=min_, max_=max_, stat=main))
            await conn.execute(
                f'UPDATE allitems SET "{stat}"="{stat}"+1 WHERE "id"=$1;',
                firstitemid)
            await conn.execute('DELETE FROM inventory WHERE "item"=$1;',
                               seconditemid)
            await conn.execute('DELETE FROM allitems WHERE "id"=$1;',
                               seconditemid)
        await ctx.send(
            _("The {stat} of your **{item}** is now **{newstat}**. The other item was"
              " destroyed.").format(stat=stat,
                                    item=item["name"],
                                    newstat=main + 1))
Exemple #53
0
 def __call__(self, value):
     if not self.regexp.match(value):
         raise ValidateError(_(u"should match regex: {}"), self.regexp.pattern)
     return value
Exemple #54
0
    async def upgradeweapon(self, ctx, itemid: int):
        _("""`<itemid>` - The ID of the item to upgrade

            Upgrades an item's stat by 1.
            The price to upgrade an item is 250 times its current stat. For example, upgrading a 15 damage sword will cost $3,750.

            One handed weapons can be upgraded up to 41, two handed items up to 82.

            (This command has a cooldown of 1 hour.)""")
        async with self.bot.pool.acquire() as conn:
            item = await conn.fetchrow(
                'SELECT * FROM allitems WHERE "id"=$1 AND "owner"=$2;',
                itemid,
                ctx.author.id,
            )
            if not item:
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("You don't own an item with the ID `{itemid}`.").format(
                        itemid=itemid))
            if item["type"] != "Shield":
                stattoupgrade = "damage"
                pricetopay = int(item["damage"] * 250)
            elif item["type"] == "Shield":
                stattoupgrade = "armor"
                pricetopay = int(item["armor"] * 250)
            stat = int(item[stattoupgrade])
            hand = item["hand"]
            if (stat > 40 and hand != "both") or (stat > 81
                                                  and hand == "both"):
                await self.bot.reset_cooldown(ctx)
                return await ctx.send(
                    _("Your weapon already reached the maximum upgrade level.")
                )

        if not await ctx.confirm(
                _("Are you sure you want to upgrade this item: {item}? It will cost"
                  " **${pricetopay}**.").format(item=item["name"],
                                                pricetopay=pricetopay)):
            return await ctx.send(_("Weapon upgrade cancelled."))
        if not await checks.has_money(self.bot, ctx.author.id, pricetopay):
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(
                _("You are too poor to upgrade this item. The upgrade costs"
                  " **${pricetopay}**, but you only have **${money}**.").
                format(pricetopay=pricetopay,
                       money=ctx.character_data["money"]))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                f'UPDATE allitems SET {stattoupgrade}={stattoupgrade}+1 WHERE "id"=$1;',
                itemid,
            )
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                pricetopay,
                ctx.author.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=ctx.author.id,
                to=2,
                subject="money",
                data={"Amount": pricetopay},
                conn=conn,
            )
        await self.bot.cache.update_profile_cols_rel(ctx.author.id,
                                                     money=-pricetopay)
        await ctx.send(
            _("The {stat} of your **{item}** is now **{newstat}**. **${pricetopay}**"
              " has been taken off your balance.").format(
                  stat=stattoupgrade,
                  item=item["name"],
                  newstat=int(item[stattoupgrade]) + 1,
                  pricetopay=pricetopay,
              ))
Exemple #55
0
    def __call__(self, value):
        result = self.to_json(value)
        if result is self.NOT_JSON:
            raise ValidateError(_("Cannot decode JSON {}"), str(value))

        return result
Exemple #56
0
class GameMaster(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.top_auction = None

    @is_gm()
    @commands.command(brief=_("Publish an announcement"))
    @locale_doc
    async def publish(self, ctx, message: discord.Message):
        _("Publish a message from an announement channel")
        try:
            await message.publish()
            await ctx.send(_("Message has been published!"))
        except discord.Forbidden:
            await ctx.send(
                _("This message is not from an announcement channel!"))

    @is_gm()
    @commands.command(aliases=["cleanshop", "cshop"],
                      hidden=True,
                      brief=_("Clean up the shop"))
    @locale_doc
    async def clearshop(self, ctx):
        _("""Remove items from the shop that have been there for more than 14 days, returning them to the owners' inventories.

            Only Game Masters can use this command.""")
        async with self.bot.pool.acquire() as conn:
            timed_out = await conn.fetch(
                """DELETE FROM market WHERE "published" + '14 days'::interval < NOW() RETURNING *;""",
                timeout=600,
            )
            await conn.executemany(
                'INSERT INTO inventory ("item", "equipped") VALUES ($1, $2);',
                [(i["item"], False) for i in timed_out],
                timeout=600,
            )
        await ctx.send(
            _("Cleared {num} shop items which timed out.").format(
                num=len(timed_out)))

    @is_gm()
    @commands.command(hidden=True,
                      aliases=["gmcdc"],
                      brief=_("Clear donator cache for a user"))
    @locale_doc
    async def gmcleardonatorcache(self, ctx, *, other: MemberConverter):
        _("""`<other>` - A server member

            Clears the cached donator rank for a user globally, allowing them to use the new commands after donating.

            Only Game Masters can use this command.""")
        await self.bot.clear_donator_cache(other)
        await ctx.send(_("Done"))

    @is_gm()
    @commands.command(hidden=True, brief=_("Bot-unban a user"))
    @locale_doc
    async def unban(self, ctx, *, other: discord.User):
        _("""`<other>` - A discord User

            Unbans a user from the bot, allowing them to use commands and reactions again.

            Only Game Masters can use this command.""")
        try:
            self.bot.bans.remove(other.id)
            await ctx.send(_("Unbanned: {other}").format(other=other.name))
        except ValueError:
            await ctx.send(
                _("{other} is not banned.").format(other=other.name))

    @is_gm()
    @commands.command(hidden=True, brief=_("Create money"))
    @locale_doc
    async def gmgive(self, ctx, money: int, other: UserWithCharacter):
        _("""`<money>` - the amount of money to generate for the user
            `<other>` - A discord User with a character

            Gives a user money without subtracting it from the command author's balance.

            Only Game Masters can use this command.""")
        await self.bot.pool.execute(
            'UPDATE profile SET money=money+$1 WHERE "user"=$2;', money,
            other.id)
        await ctx.send(
            _("Successfully gave **${money}** without a loss for you to **{other}**."
              ).format(money=money, other=other))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** gave **${money}** to **{other}**.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Remove money"))
    @locale_doc
    async def gmremove(self, ctx, money: int, other: UserWithCharacter):
        _("""`<money>` - the amount of money to remove from the user
            `<other>` - a discord User with character

            Removes money from a user without adding it to the command author's balance.

            Only Game Masters can use this command.""")
        await self.bot.pool.execute(
            'UPDATE profile SET money=money-$1 WHERE "user"=$2;', money,
            other.id)
        await ctx.send(
            _("Successfully removed **${money}** from **{other}**.").format(
                money=money, other=other))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** removed **${money}** from **{other}**.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Delete a character"))
    @locale_doc
    async def gmdelete(self, ctx, other: UserWithCharacter):
        _("""`<other>` - a discord User with character

            Delete a user's profile. The user cannot be a Game Master.

            Only Game Masters can use this command.""")
        if other.id in ctx.bot.config.game_masters:  # preserve deletion of admins
            return await ctx.send(_("Very funny..."))
        async with self.bot.pool.acquire() as conn:
            g = await conn.fetchval(
                'DELETE FROM guild WHERE "leader"=$1 RETURNING id;', other.id)
            if g:
                await conn.execute(
                    'UPDATE profile SET "guildrank"=$1, "guild"=$2 WHERE "guild"=$3;',
                    "Member",
                    0,
                    g,
                )
                await conn.execute(
                    'UPDATE city SET "owner"=1 WHERE "owner"=$1;', g)
            await conn.execute(
                'UPDATE profile SET "marriage"=$1 WHERE "marriage"=$2;', 0,
                other.id)
            await conn.execute(
                'DELETE FROM children WHERE "father"=$1 OR "mother"=$1;',
                other.id)
        await self.bot.pool.execute('DELETE FROM profile WHERE "user"=$1;',
                                    other.id)
        await ctx.send(_("Successfully deleted the character."))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** deleted **{other}**.")

    @is_gm()
    @commands.command(hidden=True, brief=_("Rename a character"))
    @locale_doc
    async def gmrename(self, ctx, target: UserWithCharacter):
        _("""`<target>` - a discord User with character

            Rename a user's profile. The user cannot be a Game Master.

            Only Game Masters can use this command.""")
        if target.id in ctx.bot.config.game_masters:  # preserve renaming of admins
            return await ctx.send(_("Very funny..."))

        await ctx.send(
            _("What shall the character's name be? (min. 3 letters, max. 20)"))

        def mycheck(amsg):
            return (amsg.author == ctx.author and amsg.channel == ctx.channel
                    and len(amsg.content) < 21 and len(amsg.content) > 2)

        try:
            name = await self.bot.wait_for("message",
                                           timeout=60,
                                           check=mycheck)
        except asyncio.TimeoutError:
            return await ctx.send(_("Timeout expired."))

        await self.bot.pool.execute(
            'UPDATE profile SET "name"=$1 WHERE "user"=$2;', name.content,
            target.id)
        await ctx.send(_("Renamed."))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** renamed **{target}** to **{name.content}**.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Create an item"))
    @locale_doc
    async def gmitem(
            self,
            ctx,
            stat: int,
            owner: UserWithCharacter,
            item_type: str.title,
            value: IntFromTo(0, 100000000),
            *,
            name: str,
    ):
        _("""`<stat>` - the generated item's stat, must be between 0 and 100
            `<owner>` - a discord User with character
            `<item_type>` - the generated item's type, must be either Sword, Shield, Axe, Wand, Dagger, Knife, Spear, Bow, Hammer, Scythe or Howlet
            `<value>` - the generated item's value, a whole number from 0 to 100,000,000
            `<name>` - the generated item's name

            Generate a custom item for a user.

            Only Game Masters can use this command.""")
        if item_type not in self.bot.config.item_types:
            return await ctx.send(_("Invalid item type."))
        if not 0 <= stat <= 100:
            return await ctx.send(_("Invalid stat."))
        if item_type in ["Scythe", "Bow", "Howlet"]:
            hand = "both"
        elif item_type in ["Spear", "Wand"]:
            hand = "right"
        elif item_type == "Shield":
            hand = "left"
        else:
            hand = "any"
        await self.bot.create_item(
            name=name,
            value=value,
            type_=item_type,
            damage=stat if item_type != "Shield" else 0,
            armor=stat if item_type == "Shield" else 0,
            hand=hand,
            owner=owner,
        )

        message = (
            f"{ctx.author} created a {item_type} with name {name} and stat {stat}."
        )

        await ctx.send(_("Done."))
        await self.bot.http.send_message(self.bot.config.gm_log_channel,
                                         message)
        for user in self.bot.owner_ids:
            user = await self.bot.get_user_global(user)
            await user.send(message)

    @is_gm()
    @commands.command(hidden=True, brief=_("Create crates"))
    @locale_doc
    async def gmcrate(self, ctx, rarity: str.lower, amount: int,
                      target: UserWithCharacter):
        _("""`<rarity>` - the crates' rarity, can be common, uncommon, rare, magic or legendary
            `<amount>` - the amount of crates to generate for the given user, can be negative
            `<target>` - A discord User with character

            Generate a set amount of crates of one rarity for a user.

            Only Game Masters can use this command.""")
        if rarity not in ["common", "uncommon", "rare", "magic", "legendary"]:
            return await ctx.send(
                _("{rarity} is not a valid rarity.").format(rarity=rarity))
        await self.bot.pool.execute(
            f'UPDATE profile SET "crates_{rarity}"="crates_{rarity}"+$1 WHERE'
            ' "user"=$2;',
            amount,
            target.id,
        )
        await ctx.send(
            _("Successfully gave **{amount}** {rarity} crates to **{target}**."
              ).format(amount=amount, target=target, rarity=rarity))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** gave **{amount}** {rarity} crates to **{target}**.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Generate XP"))
    @locale_doc
    async def gmxp(self, ctx, target: UserWithCharacter, amount: int):
        _("""`<target>` - A discord User with character
            `<amount>` - The amount of XP to generate, can be negative

            Generates a set amount of XP for a user.

            Only Game Masters can use this command.""")
        await self.bot.pool.execute(
            'UPDATE profile SET "xp"="xp"+$1 WHERE "user"=$2;', amount,
            target.id)
        await ctx.send(
            _("Successfully gave **{amount}** XP to **{target}**.").format(
                amount=amount, target=target))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** gave **{amount}** XP to **{target}**.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Wipe someone's donation perks."))
    @locale_doc
    async def gmwipeperks(self, ctx, target: UserWithCharacter):
        _("""`<target>` - A discord User with character

            Wipe a user's donation perks. This will:
              - set their background to the default
              - set both their classes to No Class
              - reverts all items to their original type and name
              - sets their guild's member limit to 50

            Only Game Masters can use this command.""")
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "background"=$1, "class"=$2 WHERE "user"=$3;',
                "0",
                ["No Class", "No Class"],
                target.id,
            )
            await conn.execute(
                'UPDATE allitems SET "name"=CASE WHEN "original_name" IS NULL THEN'
                ' "name" ELSE "original_name" END, "type"=CASE WHEN "original_type" IS'
                ' NULL THEN "type" ELSE "original_type" END WHERE "owner"=$1;',
                target.id,
            )
            await conn.execute(
                'UPDATE guild SET "memberlimit"=$1 WHERE "leader"=$2;', 50,
                target.id)

        await ctx.send(
            _("Successfully reset {target}'s background, class, item names and guild"
              " member limit.").format(target=target))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** reset **{target}**'s donator perks.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Reset someone's classes"))
    @locale_doc
    async def gmresetclass(self, ctx, target: UserWithCharacter):
        _("""`<target>` - a discord User with character

            Reset a user's classes to No Class. They can then choose their class again for free.

            Only Game Masters can use this command.""")
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                """UPDATE profile SET "class"='{"No Class", "No Class"}' WHERE "user"=$1;""",
                target.id,
            )

        await ctx.send(
            _("Successfully reset {target}'s class.").format(target=target))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** reset **{target}**'s class.",
        )

    @is_gm()
    @user_cooldown(604800)  # 7 days
    @commands.command(hidden=True, brief=_("Sign an item"))
    @locale_doc
    async def gmsign(self, ctx, itemid: int, *, text: str):
        _("""`<itemid>` - the item's ID to sign
            `<text>` - The signature to write, must be less than 50 characters combined with the Game Master's tag

            Sign an item. The item's signature is visible in a user's inventory.

            Only Game Masters can use this command.
            (This command has a cooldown of 7 days.)""")
        text = f"{text} (signed by {ctx.author})"
        if len(text) > 50:
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("Text exceeds 50 characters."))
        await self.bot.pool.execute(
            'UPDATE allitems SET "signature"=$1 WHERE "id"=$2;', text, itemid)
        await ctx.send(_("Item successfully signed."))
        await self.bot.http.send_message(
            self.bot.config.gm_log_channel,
            f"**{ctx.author}** signed {itemid} with *{text}*.",
        )

    @is_gm()
    @commands.command(hidden=True, brief=_("Start an auction"))
    @locale_doc
    async def gmauction(self, ctx, *, item: str):
        _("""`<item>` - a description of what is being auctioned

            Starts an auction on the support server. Users are able to bid. The auction timeframe extends by 30 minutes if users keep betting.
            The auction ends when no user bids in a 30 minute timeframe.

            The item is not given automatically and the needs to be given manually.

            Only Game Masters can use this command.""")
        channel = discord.utils.get(
            self.bot.get_guild(self.bot.config.support_server_id).channels,
            name="auctions",
        )
        await channel.send(
            f"{ctx.author.mention} started auction on **{item}**! Please use"
            f" `{ctx.prefix}bid amount` to raise the bid. If no more bids are sent"
            " within a 30 minute timeframe, the auction is over.")
        self.top_auction = (ctx.author, 0)
        last_top_bid = -1
        while True:
            await asyncio.sleep(60 * 30)
            new_top_bid = self.top_auction[1]
            if new_top_bid == last_top_bid:
                break
            last_top_bid = new_top_bid
        await channel.send(
            f"**{item}** sold to {self.top_auction[0].mention} for"
            f" **${self.top_auction[1]}**!")
        self.top_auction = None

    @has_char()
    @commands.command(hidden=True, brief=_("Bid on an auction"))
    @locale_doc
    async def bid(self, ctx, amount: IntGreaterThan(0)):
        _("""`<amount>` - the amount of money to bid, must be higher than the current highest bid

            Bid on an ongoing auction.

            The amount is removed from you as soon as you bid and given back if someone outbids you. This is to prevent bidding impossibly high and then not paying up."""
          )
        if self.top_auction is None:
            return await ctx.send(_("No auction running."))
        if amount <= self.top_auction[1]:
            return await ctx.send(_("Bid too low."))
        if ctx.character_data["money"] < amount:
            return await ctx.send(_("You are too poor."))
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                self.top_auction[1],
                self.top_auction[0].id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=1,
                to=self.top_auction[0].id,
                subject="bid",
                data={"Amount": self.top_auction[1]},
            )
            self.top_auction = (ctx.author, amount)
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                amount,
                ctx.author.id,
            )
            await self.bot.log_transaction(ctx,
                                           from_=ctx.author.id,
                                           to=2,
                                           subject="bid",
                                           data={"Amount": amount})
        await ctx.send(_("Bid submitted."))
        channel = discord.utils.get(
            self.bot.get_guild(self.bot.config.support_server_id).channels,
            name="auctions",
        )
        await channel.send(
            f"**{ctx.author.mention}** bids **${amount}**! Check above for what's being"
            " auctioned.")

    @is_gm()
    @commands.command(aliases=["gmcd", "gmsetcd"],
                      hidden=True,
                      brief=_("Set a cooldown"))
    @locale_doc
    async def gmsetcooldown(
        self,
        ctx,
        user: Union[discord.User, int],
        command: str,
        cooldown: IntGreaterThan(-1) = 0,
    ):
        _("""`<user>` - A discord User or their User ID
            `<command>` - the command which the cooldown is being set for (subcommands in double quotes, i.e. "guild create")
            `[cooldown]` - The cooldown to set for the command in seconds, must be greater than -1; defaults to 0

            Set a cooldown for a user and commmand. If the cooldown is 0, it will be removed.

            Only Game Masters can use this command.""")
        if not isinstance(user, int):
            user_id = user.id
        else:
            user_id = user

        if cooldown == 0:
            result = await self.bot.redis.execute("DEL",
                                                  f"cd:{user_id}:{command}")
        else:
            result = await self.bot.redis.execute("EXPIRE",
                                                  f"cd:{user_id}:{command}",
                                                  cooldown)

        if result == 1:
            await ctx.send(_("The cooldown has been updated!"))
            await self.bot.http.send_message(
                self.bot.config.gm_log_channel,
                f"**{ctx.author}** set **{user}**'s cooldown to {cooldown}.",
            )
        else:
            await ctx.send(
                _("Cooldown setting unsuccessful (maybe you mistyped the command name"
                  " or there is no cooldown for the user?)."))
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import json
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QCursor
from deepin_menu.menu import Menu, CheckableMenuItem

from views.subtitles import get_subtitle_from_movie
from utils.config import *
from utils.i18n import _
from utils.utils import utils

frame_sub_menu = [
    CheckableMenuItem("proportion:radio:_p_default", _("Default"), True),
    CheckableMenuItem("proportion:radio:_p_4_3", "4:3"),
    CheckableMenuItem("proportion:radio:_p_16_9", "16:9"),
    CheckableMenuItem("proportion:radio:_p_16_10", "16:10"),
    CheckableMenuItem("proportion:radio:_p_1_85_1", "1.85:1"),
    CheckableMenuItem("proportion:radio:_p_2_35_1", "2.35:1"),
    None,
    CheckableMenuItem("scale:radio:_s_0_5", "0.5"),
    CheckableMenuItem("scale:radio:_s_1", "1", True),
    CheckableMenuItem("scale:radio:_s_1_5", "1.5"),
    CheckableMenuItem("scale:radio:_s_2", "2"),
    None,
    ("_turn_right", _("Rotate 90 degree clockwise"), (), (), config.hotkeysFrameSoundRotateClockwise),
    ("_turn_left", _("Rotate 90 degree counterclockwise"), (), (), config.hotkeysFrameSoundRotateAnticlockwise),
    ("_flip_horizontal", _("Flip horizontally")),
    ("_flip_vertial", _("Flip vertically")),
Exemple #58
0
    async def race(self, ctx):
        _("""Pick or change your race. This can be chosen as long as you have reset points left.

            Each race has a different DMG/DEF distribution:
              - Orc: +4 defense, +0 damage
              - Dwarf: +3 defense, +1 damage
              - Human: +2 defense, +2 damage
              - Elf: +1 defense, +3 damage
              - Jikill: +0 defense, +4 damage

            By default, you are a human.

            After picking the race, you will be asked a personal question, the answer may affect something."""
          )
        if not is_nothing(ctx):
            if ctx.character_data["reset_points"] < 1:
                return await ctx.send(_("You have no more reset points."))
            if not await ctx.confirm(
                    _("You already chose a race. This change now will cost you a reset"
                      " point. Are you sure?")):
                return
        embeds = [
            discord.Embed(
                title=_("Human"),
                description=
                _("Humans are a team. They work and fight hand in hand and never give"
                  " up, even when some of their friends already died. Their rage and"
                  " hate against enemies makes them attack efficient and"
                  " concentrated. Their attack and defense skills are pretty equal."
                  ),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Dwarf"),
                description=
                _("Dwarves are the masters of their forge. Although they're very"
                  " small, they can deal a lot of damage with their self-crafted"
                  " equipment. Because of their reflexes, they have more defense than"
                  " attack. Want an ale?"),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Elf"),
                description=
                _("Elves are the masteres of camouflage. They melt with their"
                  " enviroment to attack enemies without their knowing. Their bound"
                  " to nature made them good friends of the wild spirits which they"
                  " can call for help and protection. They have more attack than"
                  " defense."),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Orc"),
                description=
                _("Orcs are a friendly race based on their rituals of calling their"
                  " ancestors to bless the rain and the deeds of their tribe. More"
                  " ugly than nice, they mostly avoid being attacked by enemies. If"
                  " they can't avoid a fight, then they have mostly no real damage,"
                  " only a bit, but a huge armour. Who cares about the damage as long"
                  " as you don't die?"),
                color=self.bot.config.primary_colour,
            ),
            discord.Embed(
                title=_("Jikill"),
                description=
                _("Jikills are dwarflike creatures with one eye in the middle of"
                  " their face, which lets them have a big and huge forehead, big"
                  " enough for their brain which can kill enemies. These sensitive"
                  " creatures are easily knocked out."),
                color=self.bot.config.primary_colour,
            ),
        ]
        races = ["Human", "Dwarf", "Elf", "Orc", "Jikill"]
        questions = {
            "Human": {
                "question":
                _("One of my biggest regrets is..."),
                "answers": [
                    _("...that I never confessed my true love, and now she is dead."
                      ),
                    _("...that I have never been to the funeral of my parents."
                      ),
                    _("...that I betrayed my best friend."),
                ],
            },
            "Dwarf": {
                "question":
                _("One of my proudest creations is..."),
                "answers": [
                    _("...a perfected ale keg."),
                    _("...a magical infused glove."),
                    _("...a bone-forged axe."),
                ],
            },
            "Elf": {
                "question":
                _("My favourite spirit of the wild is..."),
                "answers": [
                    _("...Beringor, the bear spirit."),
                    _("...Neysa, the tiger spirit."),
                    _("...Avril, the wolf spirit."),
                    _("...Sambuca, the eagle spirit."),
                ],
            },
            "Orc": {
                "question":
                _("The ancestor that gives me my strength is..."),
                "answers": [
                    _("...my sister."),
                    _("...my father."),
                    _("...my grandmother."),
                    _("...my uncle."),
                ],
            },
            "Jikill": {
                "question":
                _("The biggest action that can outknock me, is..."),
                "answers": [
                    _("...noise"),
                    _("...spiritual pain"),
                    _("...extreme temperatures."),
                    _("...strange and powerful smells."),
                ],
            },
        }
        race_ = await self.bot.paginator.ChoosePaginator(
            extras=embeds, choices=races).paginate(ctx)
        cv = questions[race_]
        answer = await self.bot.paginator.Choose(
            title=cv["question"], entries=cv["answers"],
            return_index=True).paginate(ctx)

        async with self.bot.pool.acquire() as conn:
            if not is_nothing(ctx):
                await conn.execute(
                    'UPDATE profile SET "reset_points"="reset_points"-$1 WHERE'
                    ' "user"=$2;',
                    1,
                    ctx.author.id,
                )
                await self.bot.cache.update_profile_cols_rel(ctx.author.id,
                                                             reset_points=-1)
            await conn.execute(
                'UPDATE profile SET "race"=$1, "cv"=$2 WHERE "user"=$3;',
                race_,
                answer,
                ctx.author.id,
            )
        await self.bot.cache.update_profile_cols_abs(ctx.author.id,
                                                     race=race_,
                                                     cv=answer)
        await ctx.send(_("You are now a {race}.").format(race=race_))
Exemple #59
0
    def payment_pay(self, *args, **request_data):
        """Checks payment availability for customer.
        Parameters must be sent as json object. Request data looks like:
        {
              'AccountId': '1000', # Customer ID here
              'Amount': '10.00',
              'AuthCode': 'A1B2C3',
              'CardExpDate': '10/15',
              'CardFirstSix': '424242',
              'CardLastFour': '4242',
              'CardType': 'Visa',
              'Currency': 'RUB',
              'Data': '{"myProp":"myProp value"}',
              'DateTime': '2015-08-05 06:54:46',
              'Description': 'Payment description',
              'Email': '*****@*****.**',
              'InvoiceId': '1234567',
              'IpAddress': '46.251.83.16',
              'IpCity': 'Moscow',
              'IpCountry': 'RU',
              'IpDistrict': 'Moscow federal district',
              'IpLatitude': '56.329918',
              'IpLongitude': '44.009193',
              'IpRegion': 'Moscow district',
              'Name': 'CARDHOLDER NAME',
              'PaymentAmount': '10.00',  # Not found in documentation but exist in request
              'PaymentCurrency': 'RUB',  # No in docs
              'Status': 'Completed',
              'TestMode': '1',
              'Token': '477BBA133C182267FE5F086924ABDC5DB71F77BFC27F01F2843F2CDC69D89F05',
              'TransactionId': '1211506'
        }

        :param Int TransactionId: Mandatory - System transaction number.
        :param Numeric Amount: Mandatory - Payment amount from widget. Dot as separator, two digits after dot.
        :param String Currency: Mandatory - Currency: RUB/USD/EUR/GBP from widget parameters.
        :param String InvoiceId: Not mandatory - Order number from widget parameters.
        :param String AccountId: Mandatory - Customer identifier from widget parameters.
        :param String SubscriptionId: Not mandatory - Subscription identifier from widget parameters (for recurrent payments).
        :param String Name: Not mandatory - Card holder name.
        :param String Email: Payer's e-mail
        :param DateTime: Mandatory - Payment creation date/time in UTC (yyyy-MM-dd HH:mm:ss).
        :param String IpAddress: Not mandatory - Payer IP-address
        :param String IpCountry: Not mandatory - Payer's country double-chars code (according to ISO3166-1)
        :param String IpCity: Not mandatory - Payer's city
        :param String IpRegion: Not mandatory - Payer's region.
        :param String IpDistrict: Not mandatory - Payer's district.
        :param String CardFirstSix: Mandatory - Credit card first 6 digits
        :param String CardLastFour: Mandatory - Credit card last 6 digits
        :param String CardType: Mandatory - Card payment system: Visa or MasterCard or Maestro
        :param String CardExpDate: Mandatory - Card expiration date MM/YY
        :param String Issuer: Not mandatory - Issuer bank name
        :param String IssuerBankCountry: Not mandatory - Issuer bank country double-char code (according to ISO3166-1)
        :param String Description: Not mandatory - Payment description from widget parameters.
        :param Json Data: Not mandatory - Any json-data from widget.
        :param Bit TestMode: Mandatory - Test mode flag (1 or 0)
        :param String Status: Mandatory - Payment status: Completed — for single-step, Authorized — for double-step.
        :param String Token: Not mandatory - Card token for recurrent payments without card data.

        :return: Status code, looks like {'code': 0}
        """
        logbook.info("[payment_pay] Request info:{}", request_data)
        short_payment_info = dict([(key, request_data.get(key)) for key in PaymentsApi.payment_info_fields])

        # Common validation
        validation_res, validation_info = self.validate_request(request_data, short_payment_info)
        if not validation_res:
            log_error("[payment_pay] {} Payment info: {}", validation_info, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        # Currency validation
        currency = request_data['Currency']
        if not currency or currency not in conf.currency.active:
            log_error("[payment_pay] Invalid or incompatible currency: {}. Payment info: {}",
                      currency, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        # Customer validation
        customer_id = request_data['AccountId']
        customer = Customer.get_by_id(customer_id, False)
        if not customer:
            log_error("[payment_pay] Customer id '{}' not found. Payment info: {}",
                      customer_id, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        if customer.is_test_mode():
            # Payments in test mode is not allowed
            logbook.warning("[payment_pay] Customer {} in test mode. Payment info {}", customer, short_payment_info)
            return {'code': self.ERROR_OK}

        # Transaction validation
        transaction_id = request_data['TransactionId']
        transaction_count = customer.check_account_history_transaction(transaction_id)
        if transaction_count:
            # This transaction already processed
            logbook.warning("[payment_pay] Customer {}. Transaction already processed. Payment info {}",
                            customer, short_payment_info)
            return {'code': self.ERROR_OK}

        payment_description = _("Balance recharge via CloudPayments. Transaction: {}")

        # Process payment
        amount = Decimal(request_data['Amount'])
        customer.modify_balance(amount, currency, None,
                                payment_description.format(request_data['TransactionId']),
                                transaction_id=transaction_id)

        # Save customer's payment card for automated payments
        aux_data = request_data.get('Data')
        if aux_data and aux_data.get('saveAsDefault', False) is True:
            card_token = request_data.get("Token")
            if not card_token:
                log_error("[payment_pay] Customer {} wants to save card, but Token empty. Payment info: {}",
                          customer, short_payment_info)
            else:
                card = CustomerCard.add_card(customer_id, request_data['CardLastFour'], request_data['CardType'],
                                             card_token, active=True)
                logbook.info("[payment_pay] Customer {}. Add payment card: {}",
                             customer, card.display())

        # Expected successful code (no other codes were accepted for pay)
        return {"code": 0}
Exemple #60
0
    async def weapontype(self, ctx, itemid: int, new_type: str.title):
        _(
            """`<itemid>` - The ID of the item to change type
            `<new_type>` - The type to transform the item into

            Change an item's type. Once the type changed, the item becomes unsellable.

            You may not change a two-handed item into a one-handed one, or vice versa.
            This proves useful for merging items.

            Only bronze (or above) tier patrons can use this command."""
        )
        if new_type not in self.bot.config.item_types:
            return await ctx.send(_("Invalid type."))
        async with self.bot.pool.acquire() as conn:
            item = await conn.fetchrow(
                'SELECT * FROM allitems WHERE "owner"=$1 and "id"=$2;',
                ctx.author.id,
                itemid,
            )
            if not item:
                return await ctx.send(
                    _("You don't have an item with the ID `{itemid}`.").format(
                        itemid=itemid
                    )
                )

            if item["type"] == new_type:
                return await ctx.send(
                    _("The item is already a {item_type}.").format(item_type=new_type)
                )
            if new_type == "Shield":
                hand = "left"
            elif new_type in ("Spear", "Wand"):
                hand = "right"
            elif new_type in ("Bow", "Howlet", "Scythe"):
                hand = "both"
            else:
                hand = "any"

            if (item["hand"] == "both" and hand != "both") or (
                item["hand"] != "both" and hand == "both"
            ):
                return await ctx.send(
                    _(
                        "You may not change a two-handed item to a single-handed one"
                        " and vice-versa due to weapon damage reasons."
                    )
                )

            stat = item["damage"] or item["armor"]

            await conn.execute(
                'UPDATE allitems SET "type"=$1, "original_type"=CASE WHEN'
                ' "original_type" IS NULL THEN "type" ELSE "original_type" END,'
                ' "damage"=$2, "armor"=$3, "hand"=$4 WHERE "id"=$5;',
                new_type,
                0 if new_type == "Shield" else stat,
                stat if new_type == "Shield" else 0,
                hand,
                itemid,
            )
            await conn.execute(
                'UPDATE inventory SET "equipped"=$1 WHERE "item"=$2;', False, itemid
            )
        await ctx.send(
            _("The item with the ID `{itemid}` is now a `{itemtype}`.").format(
                itemid=itemid, itemtype=new_type
            )
        )