def craft(userid, recipe, n=1):
    """Crafts (a given number of) an item."""
    try:
        recipeid = find_by_name(recipe)
    except KeyError:
        return f'Error: cannot find recipe that crafts {recipe}.'

    name = items.get_attr(recipeid)
    artisan_level = users.xp_to_level(users.read_user(userid, key=users.ARTISAN_XP_KEY))
    artisan_req = get_attr(recipeid, key=LEVEL_REQ_KEY)
    if artisan_level < artisan_req:
        return f'Error: {name} has a gathering requirement ({artisan_req}) ' \
               f'higher than your artisan level ({artisan_level}).'

    inputs = get_attr(recipeid)
    loot = []
    for itemid in list(inputs.keys()):
        if users.item_in_inventory(userid, itemid, number=n * inputs[itemid]):
            loot.extend((n * inputs[itemid]) * [itemid])
        else:
            return f'Error: you do not have enough items to make {n} {items.add_plural(recipeid)} ' \
                   f'({n * inputs[itemid]} {items.add_plural(itemid)}).'

    users.update_inventory(userid, loot, remove=True)
    users.update_inventory(userid, n * [recipeid])
    xp = n * items.get_attr(recipeid, key=items.XP_KEY)
    users.update_user(userid, xp, key=users.ARTISAN_XP_KEY)

    xp_formatted = '{:,}'.format(xp)
    return f'Successfully crafted {n} {items.add_plural(recipeid)}! You have also gained {xp_formatted} artisan xp!'
    async def cancel(self, ctx):
        """Cancels your current action."""
        try:
            task = adv.get_adventure(ctx.author.id)

            adventureid = task[0]
            if adventureid == '0':
                if users.item_in_inventory(ctx.author.id, '291', '1'):
                    users.update_inventory(ctx.author.id, ['291'], remove=True)
                    adv.remove(ctx.author.id)
                    out = 'Slayer task cancelled!'
                else:
                    out = 'Error: You do not have a reaper token.'
            elif adventureid == '1':
                adv.remove(ctx.author.id)
                out = 'Killing session cancelled!'
            elif adventureid == '2':
                adv.remove(ctx.author.id)
                out = 'Quest cancelled!'
            elif adventureid == '3':
                adv.remove(ctx.author.id)
                out = 'Gather cancelled!'
            else:
                out = f'Error: Invalid Adventure ID {adventureid}'

        except NameError:
            out = 'You are not currently doing anything.'
        await ctx.send(out)
Beispiel #3
0
def buy(userid, item, number):
    """Buys (a given amount) of an item and places it in the user's inventory."""
    try:
        itemid = find_by_name(item)
        number = int(number)
    except KeyError:
        return f'Error: {item} is not an item.'
    except ValueError:
        return f'Error: {number} is not a number.'
    item_name = get_attr(itemid)
    if item_in_shop(itemid):
        items = open_shop()
        if int(items[itemid]) in users.get_completed_quests(userid) or int(
                items[itemid]) == 0:
            value = get_attr(itemid, key=VALUE_KEY)
            cost = 4 * number * value
            if users.item_in_inventory(userid, "0", cost):
                users.update_inventory(userid, [itemid] * number)
                users.update_inventory(userid, (4 * number * value) * ["0"],
                                       remove=True)
                value_formatted = '{:,}'.format(4 * value * number)
                return f'{number} {item_name} bought for {value_formatted} coins!'
            else:
                return f'You do not have enough coins to buy this item. ({cost} coins)'
        else:
            return 'Error: You do not have the requirements to buy this item.'
    else:
        return f'Error: {item_name} not in inventory or you do not have at least {number} in your inventory.'
Beispiel #4
0
def claim(userid, itemname, number):
    try:
        itemid = find_by_name(itemname)
    except KeyError:
        return f"Error: {itemname} is not an item."

    if not users.item_in_inventory(userid, itemid, number):
        return f'You do not have {add_plural(number, itemid)} in your inventory.'

    out = '__**CLAIM**__ :moneybag:\n'

    if int(itemid) == 402:
        out += 'You have received:\n'
        gems = {25: 4, 26: 16, 27: 64, 28: 128, 463: 1024, 465: 2048}
        loot = []
        for _ in range(number):
            while True:
                gem_type = random.choice(gems.keys(), 1)[0]
                if random.randint(1, gems[gem_type]) == 1:
                    loot.append(gem_type)
                    break
        users.update_inventory(userid, loot)
        loot_counter = Counter(loot)
        for gemid in loot_counter.keys():
            out += f'{add_plural(loot_counter[gemid], gemid)}\n'
        out += f'from your {add_plural(number, itemid)}.'
        users.update_inventory(userid, number * [itemid], remove=True)
    else:
        out += f'{get_attr(itemid)} is not claimable.'
    return out
Beispiel #5
0
def has_item_reqs(userid, questid):
    """Checks if a user can do a quest based on based on whether they have the required items in their inventory."""
    item_reqs = get_attr(questid, key=ITEM_REQ_KEY)
    count = 0
    for itemid in item_reqs:
        if users.item_in_inventory(userid, itemid, item_reqs[itemid]):
            count += 1
    return count == len(item_reqs)
Beispiel #6
0
def cook(userid, food, n=1):
    """Cooks (a given number of) an item."""
    try:
        foodid = find_by_name(food, cook=True)
    except KeyError:
        return f'Cannot find food called {food} that can be cooked.'
    except TypeError:
        return f'Cannot cook {food}.'

    name = items.get_attr(foodid)
    cooking_level = users.get_level(userid, key=users.COOK_XP_KEY)
    cooking_req = get_attr(foodid, key=COOKING_REQ_KEY)
    if cooking_level < cooking_req:
        return f'{name} has a cooking requirement ({cooking_req}) higher than your cooking level ({cooking_level}).'

    burn_chance = calc_burn(userid, foodid)
    num_cooked = 0
    if burn_chance == 0:
        num_cooked = n
    else:
        for _ in range(n):
            if random.randint(1, 100) > burn_chance:
                num_cooked += 1

    inputs = get_attr(foodid)
    food_input = []
    for itemid in list(inputs.keys()):
        if users.item_in_inventory(userid,
                                   itemid,
                                   number=num_cooked * inputs[itemid]):
            food_input.extend((num_cooked * inputs[itemid]) * [itemid])
        else:
            return f'Error: you do not have enough items to make {items.add_plural(n, foodid)} ' \
                   f'({items.add_plural(n * inputs[itemid], itemid)}).'

    users.update_inventory(userid, food_input, remove=True)
    users.update_inventory(userid, num_cooked * [foodid])
    users.update_inventory(userid, (n - num_cooked) * ['469'])
    xp = XP_FACTOR * num_cooked * items.get_attr(foodid, key=items.XP_KEY)
    users.update_user(userid, xp, key=users.COOK_XP_KEY)
    level_after = users.xp_to_level(users.read_user(userid, users.COOK_XP_KEY))

    xp_formatted = '{:,}'.format(xp)
    out = f'After cooking {items.add_plural(n, foodid)}, you successfully cook ' \
          f'{num_cooked} and burn {n - num_cooked}! ' \
          f'You have also gained {xp_formatted} cooking xp! '
    if level_after > cooking_level:
        out += f'You have also gained {level_after - cooking_level} cooking levels!'
    return out
Beispiel #7
0
def craft(userid, recipe, n=1):
    """Crafts (a given number of) an item."""
    try:
        recipeid = find_by_name(recipe.lower())
    except KeyError:
        return f'Cannot find recipe that crafts {recipe}.'
    except TypeError:
        return f'Cannot craft {recipe}.'

    name = items.get_attr(recipeid)
    artisan_level = users.get_level(userid, key=users.ARTISAN_XP_KEY)
    artisan_req = get_attr(recipeid, key=ARTISAN_REQ_KEY)
    if artisan_level < artisan_req:
        return f'Error: {name} has a artisan requirement ({artisan_req}) ' \
               f'higher than your artisan level ({artisan_level}).'

    inputs = get_attr(recipeid)
    recipe_input = []
    for itemid in list(inputs.keys()):
        if users.item_in_inventory(userid, itemid, number=n * inputs[itemid]):
            recipe_input.extend((n * inputs[itemid]) * [itemid])
        else:
            return f'Error: you do not have enough items to make {items.add_plural(n, recipeid)} ' \
                   f'({items.add_plural(n * inputs[itemid], itemid)}).'
    bonus = 0
    if artisan_level == 99:
        for _ in range(n):
            if random.randint(1, 20) == 1:
                bonus += 1
    equipment = users.read_user(userid, users.EQUIPMENT_KEY)
    goldsmith_bonus = 2 if equipment['9'] == '494' and recipeid == '59' else 1

    users.update_inventory(userid, recipe_input, remove=True)
    users.update_inventory(userid, (n + bonus) * [recipeid])
    xp = XP_FACTOR * goldsmith_bonus * n * items.get_attr(recipeid,
                                                          key=items.XP_KEY)
    users.update_user(userid, xp, key=users.ARTISAN_XP_KEY)
    level_after = users.xp_to_level(
        users.read_user(userid, users.ARTISAN_XP_KEY))

    xp_formatted = '{:,}'.format(xp)
    out = f'Successfully crafted {items.add_plural(n, recipeid)}! You have also gained {xp_formatted} artisan xp! '
    if bonus > 0:
        out += f'Due to your 99 artisan perk, you have also created an extra {items.add_plural(bonus, recipeid)}! '
    if level_after > artisan_level:
        out += f'You have also gained {level_after - artisan_level} artisan levels!'
    return out
Beispiel #8
0
def start_clue(userid, difficulty):
    """Starts a clue scroll."""
    out = f'{CLUE_HEADER}'
    if not adv.is_on_adventure(userid):
        scrollid = str(EASY_CLUE_SCROLL_ID + difficulty - 1)
        if not users.item_in_inventory(userid, scrollid):
            return f'Error: you do not have a {DIFFICULTY[difficulty]} clue scroll in your inventory.'
        users.update_inventory(userid, [scrollid], remove=True)

        length = math.floor(calc_length(userid, difficulty) / 60)
        clue = adv.format_line(4, userid, adv.get_finish_time(length * 60),
                               difficulty, length)
        adv.write(clue)
        out += f'You are now doing a {DIFFICULTY[difficulty]} clue scroll for {length} minutes.'
    else:
        out = adv.print_adventure(userid)
        out += adv.print_on_adventure_error('clue scroll')
    return out
def sell(userid, item, number):
    """Sells (a given amount) of an item from a user's inventory."""
    try:
        itemid = find_by_name(item)
        number = int(number)
    except KeyError:
        return f'Error: {item} is not an item.'
    except ValueError:
        return f'Error: {number} is not a number.'

    item_name = get_attr(itemid)
    if users.item_in_inventory(userid, itemid, number=number):
        value = get_attr(itemid, key=VALUE_KEY)
        users.update_inventory(userid, [itemid] * number, remove=True)
        ac.update_account(userid, number * value)
        value_formatted = '{:,}'.format(value * number)
        return f'{number} {item_name} sold for G${value_formatted}!'
    else:
        return f'Error: {item_name} not in inventory or you do not have at least {number} in your inventory.'
Beispiel #10
0
def print_recipe(userid, recipe):
    """Prints details related to a particular recipe."""
    try:
        recipeid = find_by_name(recipe)
    except KeyError:
        return f'Error: cannot find recipe that crafts {recipe}.'

    out = f'{CRAFT_HEADER}'\
          f'**Name**: {items.get_attr(recipeid).title()}\n'\
          f'**Artisan Requirement**: {get_attr(recipeid, key=ARTISAN_REQ_KEY)}\n\n'\
          f'**Inputs**:\n'
    inputs = get_attr(recipeid, key=INPUTS_KEY)
    for inputid in list(inputs.keys()):
        if users.item_in_inventory(userid, inputid, inputs[inputid]):
            out += f'~~{items.add_plural(inputs[inputid], inputid)}~~\n'
        else:
            out += f'{items.add_plural(inputs[inputid], inputid)}\n'

    return out
Beispiel #11
0
def drink(userid, name):
    try:
        itemid = find_by_name(name)
    except KeyError:
        return f'Error: {name} does not exist.'
    item_name = get_attr(itemid)

    is_pot = get_attr(itemid, key=POT_KEY)
    if is_pot:
        if users.item_in_inventory(userid, itemid):
            users.update_inventory(userid, [itemid], remove=True)
            equipment = users.read_user(userid, key=users.EQUIPMENT_KEY)
            equipment['15'] = str(itemid)
            users.update_user(userid, equipment, key=users.EQUIPMENT_KEY)
        else:
            return f"You do not have any {add_plural(0, itemid)} in your inventory."
    else:
        return f"{item_name} isn't a potion!"

    out = f'You drank the {item_name}! Your stats will be increased for your next adventure.'
    return out
Beispiel #12
0
def print_details(userid, questid):
    """Prints the details of a quest."""
    try:
        name = get_attr(questid)
    except KeyError:
        return f'Error: There is no quest with number {questid}.'

    out = f'{QUEST_HEADER}'

    out += f'**{questid}: {name}**\n'
    out += f'*{get_attr(questid, key=DESCRIPTION_KEY)}*\n\n'

    out += f'**Base Time**: {get_attr(questid, key=TIME_KEY)} minutes.\n'

    if int(questid) in users.get_completed_quests(userid):
        out += f'\n*{get_attr(questid, key=SUCCESS_KEY)}*\n'

    quest_reqs = get_attr(questid, key=QUEST_REQ_KEY)
    if len(quest_reqs) > 0:
        user_quests = set(users.get_completed_quests(userid))
        out += f'\n**Quest Requirements**:\n'
        for quest_req in quest_reqs:
            if quest_req in user_quests:
                out += f'~~{quest_req}. {get_attr(quest_req)}~~\n'
            else:
                out += f'{quest_req}. {get_attr(quest_req)}\n'

    item_reqs = get_attr(questid, key=ITEM_REQ_KEY)
    if len(item_reqs) > 0:
        out += f'\n**Item Requirements**:\n'
        for itemid in item_reqs:
            if users.item_in_inventory(userid, itemid, item_reqs[itemid]):
                out += f'~~{items.add_plural(item_reqs[itemid], itemid)}~~\n'
            else:
                out += f'{items.add_plural(item_reqs[itemid], itemid)}\n'

    out += f'\nIf you would like to do this quest, type `~quest start {questid}`.'
    return out
Beispiel #13
0
    async def deathmatch(self, ctx, opponent='rand', bet=None):
        """Allows users to duke it out in a 1v1 match."""
        if ctx.channel.id == DUEL_CHANNEL or ctx.channel.id in GENERAL_CHANNELS:
            author_name = get_display_name(ctx.author)
            if bet is not None:
                if users.read_user(ctx.author.id, key=users.IRONMAN_KEY):
                    await ctx.send('Ironmen cannot start staked deathmatches.')
                    return
                try:
                    bet = users.parse_int(bet)
                except ValueError:
                    await ctx.send(f'{bet} does not represent a valid number.')
                bet_formatted = '{:,}'.format(bet)
                if not users.item_in_inventory(ctx.author.id, '0', bet):
                    await ctx.send(f'You do not have {bet_formatted} coins.')
                    return
                try:
                    opponent_member = parse_name(ctx.message.guild, opponent)
                except NameError:
                    await ctx.send(f'{opponent} not found in server.')
                    return
                except AmbiguousInputError as members:
                    await ctx.send(
                        f'Input {opponent} can refer to multiple people ({members})'
                    )
                    return
                if opponent_member.id == ctx.author.id:
                    await ctx.send('You cannot fight yourself.')
                    return
                if users.read_user(opponent_member.id, key=users.IRONMAN_KEY):
                    await ctx.send(
                        'You cannot start a staked deathmatch with an ironman.'
                    )
                    return
                bet_formatted = '{:,}'.format(bet)
                opponent_name = get_display_name(opponent_member)
                if not users.item_in_inventory(opponent_member.id, '0', bet):
                    await ctx.send(
                        f'{opponent_name} does not have {bet_formatted} coins.'
                    )
                    return
                users.update_inventory(ctx.author.id, bet * ['0'], remove=True)
                out = f'Deathmatch set up between {author_name} and {opponent_member.mention} with bet ' \
                      f'{bet_formatted} coins! To confirm this match, {opponent_name} must react to ' \
                      f'this message with a :thumbsup: in the next minute. If a minute passes or if the ' \
                      f'challenger reacts to this message, the deathmatch will be cancelled and the deposit ' \
                      f'refunded.'
                msg = await ctx.send(out)
                await msg.add_reaction('\N{THUMBS UP SIGN}')

                while True:
                    try:
                        reaction, user = await self.bot.wait_for(
                            'reaction_add', timeout=60)
                        if str(reaction.emoji
                               ) == '👍' and user == opponent_member:
                            users.update_inventory(opponent_member.id,
                                                   bet * ['0'],
                                                   remove=True)
                            deathmatch_messages = dm.do_deathmatch(
                                ctx.author, opponent_member, bet=bet_formatted)
                            for message in deathmatch_messages[:-1]:
                                await msg.edit(content=message)
                                await asyncio.sleep(1)
                            users.update_inventory(deathmatch_messages[-1],
                                                   2 * bet * ['0'])
                            return
                        elif user == ctx.author:
                            users.update_inventory(ctx.author.id, bet * ['0'])
                            await msg.edit(
                                content=
                                f'{author_name} has declined their challenge and '
                                f'the deposit of {bet_formatted} coins has been returned.'
                            )
                            return
                    except asyncio.TimeoutError:
                        users.update_inventory(ctx.author.id, bet * ['0'])
                        await msg.edit(
                            content=
                            f'One minute has passed and the deathmatch has been cancelled. '
                            f'The deposit of {bet_formatted} coins has been returned.'
                        )
                        return
            else:
                try:
                    opponent_member = parse_name(ctx.message.guild, opponent)
                except NameError:
                    await ctx.send(f'{opponent} not found in server.')
                    return
                except AmbiguousInputError as members:
                    await ctx.send(
                        f'Input {opponent} can refer to multiple people ({members})'
                    )
                    return
                msg = await ctx.send(dm.DEATHMATCH_HEADER)
                deathmatch_messages = dm.do_deathmatch(ctx.author,
                                                       opponent_member)
                for message in deathmatch_messages[:-1]:
                    await msg.edit(content=message)
                    await asyncio.sleep(1)
Beispiel #14
0
    async def trade(self, ctx, *args):
        """Trades to a person a number of a given object for a given price."""
        if ctx.channel.id == SHOP_CHANNEL or ctx.channel.id in GENERAL_CHANNELS:
            if users.read_user(ctx.author.id, key=users.IRONMAN_KEY):
                await ctx.send('Ironmen cannot trade.')
                return

            if len(args) < 4:
                await ctx.send(
                    'Arguments missing. Syntax is `~trade [name] [number] [item] [offer]`.'
                )
                return

            name = args[0]
            for member in ctx.guild.members:
                if name.lower() in member.name.lower():
                    name_member = member
                    break
            else:
                await ctx.send(f'{name} not found in server.')
                return
            if users.read_user(name_member.id, key=users.IRONMAN_KEY):
                await ctx.send('You cannot trade with an ironman.')
                return

            try:
                number = int(args[1])
            except ValueError:
                await ctx.send(f'{args[1]} is not a valid number.')
                return

            try:
                offer = users.parse_int(args[-1])
                itemid = items.find_by_name(' '.join(args[2:-1]))
            except ValueError:
                await ctx.send(f'{args[-1]} is not a valid offer.')
                return
            except KeyError:
                await ctx.send(f"{' '.join(args[2:-1])} is not a valid item.")
                return

            if not users.item_in_inventory(ctx.author.id, itemid, number):
                await ctx.send(
                    f'You do not have {items.add_plural(number, itemid)} in your inventory.'
                )
                return

            if not items.is_tradable(itemid):
                await ctx.send(
                    f'You can not trade this item. ({items.get_attr(itemid)})')
                return

            if not users.item_in_inventory(name_member.id, "0", offer):
                await ctx.send(
                    f'{get_display_name(name_member)} does not have enough gold to buy this many items.'
                )
                return

            name = get_display_name(ctx.author)
            offer_formatted = '{:,}'.format(offer)
            out = f'{items.SHOP_HEADER}{name.title()} wants to sell {name_member.mention} ' \
                  f'{items.add_plural(number, itemid)} for {offer_formatted} coins. To accept this offer, reply ' \
                  f'to this post with a :thumbsup:. Otherwise, this offer will expire in one minute.'
            msg = await ctx.send(out)
            await msg.add_reaction('\N{THUMBS UP SIGN}')

            while True:
                try:
                    reaction, user = await self.bot.wait_for('reaction_add',
                                                             timeout=60)
                    if str(
                            reaction.emoji
                    ) == '👍' and user == name_member and reaction.message.id == msg.id:
                        price = offer * ["0"]
                        users.update_inventory(name_member.id,
                                               price,
                                               remove=True)
                        users.update_inventory(ctx.author.id, price)
                        loot = number * [itemid]
                        users.update_inventory(ctx.author.id,
                                               loot,
                                               remove=True)
                        users.update_inventory(name_member.id, loot)

                        buyer_name = get_display_name(name_member)
                        await ctx.send(
                            f'{items.SHOP_HEADER}{name.title()} successfully sold '
                            f'{items.add_plural(number, itemid)} to {buyer_name} for '
                            f'{offer_formatted} coins!')
                        return
                except asyncio.TimeoutError:
                    await msg.edit(
                        content=
                        f'One minute has passed and your offer has been cancelled.'
                    )
                    return