Esempio n. 1
0
def start_quest(guildid, channelid, user: User, questid):
    """Assigns a user a slayer task provided they are not in the middle of another adventure."""
    from miniscape import adventures as adv

    if adv.is_on_adventure(user.id):
        out = adv.print_adventure(user.id)
        out += adv.print_on_adventure_error('quest')
        return out


    try:
        quest = Quest.objects.get(id=questid)
    except ObjectDoesNotExist:
        return f"Error: quest number {questid} does not refer to any quest."

    if quest in user.completed_quests_list:
        return "Error: you have already done this quest."

    if not user.has_quest_req_for_quest(quest):
        return "Error: you have not completed the required quests to do this quest."

    if not user.has_items_for_quest(quest):
        return "Error: you do not have all the required items to start this quest."

    out = QUEST_HEADER

    chance = calc_chance(user, quest)
    quest_length = calc_length(user, quest)
    quest_adv = adv.format_line(2, user.id, adv.get_finish_time(quest_length), guildid,
                                channelid, questid, chance)
    adv.write(quest_adv)
    out += print_quest(quest, quest_length, chance)

    return out
Esempio n. 2
0
class MiniscapeBotContext(commands.Context):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        try:
            self.user_object = User.objects.get(id=self.author.id)
        except ObjectDoesNotExist:
            self.user_object = User(
                id=self.author.id,
                name=self.author.name + '#' + self.author.discriminator,
                nick=self.author.nick if self.author.nick is not None else '')
            self.user_object.save()
            return

        # Update our user's name/nick if they differ or don't exist
        # (if they don't exist they == '')

        # TODO: Fix this, it always triggers reeeeee
        name_match = self.user_object.name == (self.author.name + '#' +
                                               self.author.discriminator)
        nick_match = self.user_object.nick == self.author.nick and self.author.nick
        if not name_match or not nick_match:
            self.user_object.nick = self.author.nick if self.author.nick is not None else ''
            self.user_object.name = self.author.name + '#' + self.author.discriminator
            self.user_object.save()
Esempio n. 3
0
def cook(user: User, food, n=1):
    """Cooks (a given number of) an item."""

    item: Item = Item.find_by_name_or_nick(food)
    if not item:
        return f'Cannot find food called {food} that can be cooked.'

    name = item.name
    cooking_level = user.cook_level
    cooking_req = item.level
    if cooking_level < cooking_req:
        return f'{name} has a cooking requirement ({cooking_req}) higher than your cooking level ({cooking_level}).'

    rr = RecipeRequirement.objects.filter(recipe__creates=item)
    if not rr:
        return "You cannot cook {name}."
    rr = rr[0]
    if user.has_item_amount_by_item(rr.item, rr.amount*n):
        negative_loot = {rr.item: rr.amount*n}
    else:
        return f'You do not have enough items to make {rr.item.pluralize(n)} ' \
               f'({rr.item.pluralize(rr.amount * n)}).'

    burn_chance = calc_burn(user, item)
    num_cooked = 0
    bonus = 0
    if burn_chance == 0:
        num_cooked = n
    else:
        for _ in range(n):
            if random.randint(1, 100) > burn_chance:
                num_cooked += 1
    if cooking_level == 99:
        bonus = random.randint(0, round(n / 20))

    user.update_inventory(negative_loot, remove=True)
    user.update_inventory({item: num_cooked})
    user.update_inventory({BURNT_FOOD: n - num_cooked})
    xp = XP_FACTOR * num_cooked * item.xp
    user.cook_xp += xp
    user.save()
    level_after = user.cook_level

    xp_formatted = '{:,}'.format(xp)
    out = f'After cooking {item.pluralize(n)}, you successfully cook ' \
          f'{num_cooked} and burn {n - num_cooked}! '
    if bonus > 0:
        out += f'Due to your cooking perk, you have also cooked an additional {item.pluralize(n)}! '
    out += 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
Esempio n. 4
0
def unequip_item(author: User, item: str):
    """Takes an item out of a user's equipment and places it into their inventory."""
    found_item = Item.find_by_name_or_nick(item)
    if not found_item:
        return f'Error: {item} does not exist.'

    item_name = found_item.name
    equipment = author.all_armour

    if found_item not in author.equipment_slots:
        return f'You do not have {item_name} equipped.'

    slot = found_item.slot - 1
    slot_name = author.equipment_slot_strs[slot]
    curr_equip = author.equipment_slots[slot]

    # Set the equipment slot
    setattr(author, slot_name, None)
    author.update_inventory(curr_equip)
    author.save()
    return f'{found_item.name} unequipped from {SLOTS[str(slot+1)]}!'
Esempio n. 5
0
def bury(author: User, itemname: str, number: int):
    """Buries (a given amount) of an item and gives the user prayer xp."""

    item: Item = Item.find_by_name_or_nick(itemname)
    if not item:
        return f'Error: {itemname} is not an item.'

    if not item.is_buryable:
        return f"You cannot bury {item.name}."

    user_items = author.get_item_by_item(item)
    if not author.has_item_amount_by_item(item, number) or not user_items:
        # TODO: Pluralize this
        return f'You do not have enough {item.name} in your inventory.'

    user_item: UserInventory = user_items[0]
    xp_difference = item.xp * number
    pre_bury_level = author.prayer_level

    author.prayer_xp += xp_difference
    author.save()

    if user_item.amount == number:
        user_item.delete()
    else:
        user_item.amount -= number
        user_item.save()

    post_bury_level = author.prayer_level
    level_difference = post_bury_level - pre_bury_level
    prayer_xp_formatted = '{:,}'.format(xp_difference)

    out = PRAYER_HEADER
    out += f'You get {prayer_xp_formatted} prayer xp from your {item.pluralize(number)}! '
    if level_difference:
        out += f'You have also gained {level_difference} prayer levels!'
    return out
Esempio n. 6
0
def craft(user: User, recipe, n=1):
    """Crafts (a given number of) an item."""

    recipeitem: Item = Item.find_by_name_or_nick(recipe)
    if not recipeitem:
        return f'Cannot find item {recipe}.'

    recipe: Recipe = Recipe.objects.filter(creates=recipeitem)
    if not recipe:
        return f'Cannot find recipe that crafts {recipeitem.name}.'
    recipe = recipe[0]

    name = recipeitem.name
    artisan_level = user.artisan_level
    artisan_req = recipe.level_requirement
    if artisan_level < artisan_req:
        return f'Error: {name} has a artisan requirement ({artisan_req}) ' \
               f'higher than your artisan level ({artisan_level}).'

    inputs = recipe.get_requirements()
    negative_loot = {}
    for rr in list(inputs):
        if user.has_item_amount_by_item(rr.item, rr.amount*n):
            negative_loot[rr.item] = rr.amount * n
        else:
            return f'Error: you do not have enough items to make {recipe.creates.pluralize(n)} ' \
                   f'({rr.item.pluralize(rr.amount * n)}).'

    bonus = random.randint(1, math.floor(n/20)) if artisan_level == 99 and n >=20 else 0

    goldsmith_bonus = 1
    if recipe == GOLD_BAR_RECIPE and GOLD_GAUNTLETS in user.equipment_slots:
        goldsmith_bonus = 2

    user.update_inventory(negative_loot, remove=True)
    user.update_inventory({recipe.creates: n + bonus})
    xp = XP_FACTOR * goldsmith_bonus * n * recipe.creates.xp
    user.artisan_xp += xp
    user.save()
    level_after = user.artisan_level

    xp_formatted = '{:,}'.format(xp)
    out = f'Successfully crafted {recipe.creates.pluralize(n)}! 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 {recipe.creates.pluralize(bonus)}! '
    if level_after > artisan_level:
        out += f'You have also gained {level_after - artisan_level} artisan levels!'
    return out
Esempio n. 7
0
def equip_item(author: User, item: str):
    """Takes an item out of a user's inventory and places it into their equipment."""
    found_item = Item.find_by_name_or_nick(item)
    if found_item is None:
        return f'Error: {item} does not exist.'

    item_level = found_item.level
    user_cb_level = author.combat_level

    # Error checking/verification
    if user_cb_level < item_level:
        return f'Error: Insufficient level to equip item ({found_item.level}). \
                Your current combat level is {user_cb_level}.'

    if not author.has_item_by_item(found_item):
        return f'Error: {found_item.name} not in inventory.'

    if not found_item.is_equippable:
        return f'Error: {item} cannot be equipped.'

    if found_item.is_max_only and not author.is_maxed:
        return f"You cannot equip this item since you do not have {author.max_possible_level} skill total."

    slot = found_item.slot - 1  # I blame coiz for starting this at slot 1 :ANGERY:
    curr_equip = author.equipment_slots[slot]

    # if found_item == curr_equip:
    #     return f"You already have {found_item.name} equipped!"

    item_name = found_item.name
    slot_name = author.equipment_slot_strs[slot]

    # Set the equipment slot
    setattr(author, slot_name, found_item)

    # Update the inventories
    author.update_inventory(curr_equip)
    author.update_inventory(found_item, remove=True)

    author.save()
    return f'{item_name} equipped to {SLOTS[str(slot+1)]}!'
Esempio n. 8
0
def calc_chance(user: User, monster: Monster, number: int, remove_food=False):
    """Calculates the chance of success of a task."""
    number = int(number)

    player_dam, player_acc, player_arm, dam_multiplier, monster_base, chance_bonus = calc_task_vars(
        user, monster)

    prayer_chance = 0
    if user.prayer_slot is not None:
        if 10 <= user.prayer_slot.id <= 12:  # if user is using protect from mage/range/melee
            monster_affinity = monster.affinity
            if monster_affinity == 0 and user.prayer_slot.id == 12\
                    or monster_affinity == 1 and user.prayer_slot.id == 11 \
                    or monster_affinity == 2 and user.prayer_slot.id == 10:
                prayer_chance = user.prayer_slot.chance

    chance = (200 * (1 + user.combat_level / 99) * player_arm) /\
             (number / 50 * monster.damage * dam_multiplier + (1 + monster.level / 200)) + chance_bonus

    if user.equipment_slots[0] == SLAYER_HELMET:
        chance = min(round(chance * 1.125), 100)

    if user.is_eating:
        food_bonus = user.active_food.food_value
        if food_bonus > 0:
            num_food = user.get_item_by_item(user.active_food)
            if num_food:
                num_food = num_food[0].amount
                chance += food_bonus if num_food >= number else int(
                    food_bonus * num_food / number)
                amount = number if num_food >= number else num_food
                if remove_food:
                    user.update_inventory({user.active_food.id: amount},
                                          remove=True)
            else:
                user.active_food = None
                user.save()

    chance += prayer_chance

    if chance > 100:
        chance = 100
    if chance < 0:
        chance = 0
    return round(chance)
Esempio n. 9
0
def calc_task_vars(user: User, monster: Monster):
    """Calculates the variables required to calculate a task's length/number."""
    user_prayer = user.prayer_slot
    equipment = user.equipment_slots
    player_dam, player_acc, player_arm, player_pray = user.equipment_stats
    monsters_fought = user.monster_kills(monster.name)
    if monsters_fought:
        monsters_fought = monsters_fought[0]
        monster_num_bonus = 1 - 0.2 * min(monsters_fought.amount / 5000, 1)
    else:
        monster_num_bonus = 1

    if user_prayer is not None:
        player_dam, player_acc, player_arm = prayer.calc_pray_bonus(user)

    monster_base = calc_monster_base(user, monster)

    player_potion = equipment[14]
    if player_potion:
        player_potion = player_potion.id
        if player_potion == 427 or player_potion == 430:
            player_acc = player_acc * 1.1 + 3
        if player_potion == 428 or player_potion == 430:
            player_dam = player_dam * 1.1 + 3
        if player_potion == 429 or player_potion == 430:
            player_arm = player_arm * 1.1 + 3
        if player_potion == 431 or player_potion == 434:
            player_acc = player_acc * 1.15 + 5
        if player_potion == 432 or player_potion == 434:
            player_dam = player_dam * 1.15 + 5
        if player_potion == 433 or player_potion == 434:
            player_arm = player_arm * 1.15 + 5

    dam_multiplier = 1 + player_acc / 200
    return tuple((player_dam, player_acc, player_arm, dam_multiplier,
                  monster_base, monster_num_bonus))
Esempio n. 10
0
def claim(person: User, name, number, other_person=None):
    """Claims items/xp from an item and returns a message."""
    item = Item.objects.filter(name__iexact=name)[0]
    if not item:
        return f"{name} is not an item."

    if not person.has_item_amount_by_name(name, number):
        return f'You do not have {item.pluralize(number)} in your inventory.'

    out = ':moneybag: __**CLAIM**__ :moneybag:\n'
    if item == GEM_ROCK:
        out += 'You have received:\n'
        gems = {
            SAPPHIRE: 4,
            EMERALD: 16,
            RUBY: 64,
            DIAMOND: 128,
            LAPIS_LAZULI: 256,
            QUARTZ: 512
        }
        loot = Counter()
        for _ in range(number):
            while True:
                gem_type = random.sample(gems.keys(), 1)[0]
                if random.randint(1, gems[gem_type]) == 1:
                    loot[gem_type] += 1
                    break
        person.update_inventory(loot)
        for gem in loot.keys():
            out += f'{gem.pluralize(loot[gem])}\n'
        out += f'from your {GEM_ROCK.pluralize(number)}.'
        person.update_inventory({GEM_ROCK: number}, remove=True)
    elif item == ANCIENT_EFFIGY:
        skills = Counter()
        for _ in range(number):
            skill = random.sample(person.xp_fields_str, 1)[0]
            skills[skill] += 1
        person.update_inventory({OPENED_ANCIENT_EFFIGY: number})
        person.update_inventory({ANCIENT_EFFIGY: number}, remove=True)
        got_pet = False
        if not person.has_item_amount_by_item(EFFY, 1):
            for _ in range(number):
                if random.randint(1, 100) == 1:
                    got_pet = True
                    person.update_inventory({EFFY: 1})
                    break

        out += f"You have received the following xp from your {ANCIENT_EFFIGY.pluralize(number)}!\n"
        for skill in skills.keys():
            xp_gained = skills[skill] * XP_PER_EFFIGY
            setattr(person, skill, getattr(person, skill) + xp_gained)
            xp_gained_formatted = '{:,}'.format(xp_gained)
            out += f"{xp_gained_formatted} {skill.replace('_', ' ')}\n"
        if got_pet:
            out += 'You have also recieved Effy, the Effigy Pet!'
        person.save()
    elif item == CHRISTMAS_CRACKER:
        if other_person:
            person.update_inventory({CHRISTMAS_CRACKER: number}, remove=True)
            loot = Counter(
                random.choices(Item.objects.filter(name__contains="partyhat"),
                               k=number))
            other_person_name = other_person.nick if other_person.nick else other_person.plain_name
            out += f'You and {other_person_name} pull the christmas cracker and '
            if random.randint(0, 1):
                out += f'**you** get the bigger end. You have received:\n'
                person.update_inventory(loot)
            else:
                out += f'**{other_person_name}** gets the bigger end. They have received:\n'
                other_person.update_inventory(loot)
            for item, value in loot.items():
                out += f'**{item.pluralize(value)}**\n'
        else:
            out += f'Please use the `~pull [number] [other_person]` command to claim the christmas crackers.'
    else:
        out += f'{item} is not claimable.'
    return out
Esempio n. 11
0
def start_runecraft(guildid, channelid, user: User, item, number=1, pure=0):
    """Starts a runecrafting session."""
    from miniscape import adventures as adv

    out = ''
    if not adv.is_on_adventure(user.id):
        item: Item = Item.find_by_name_or_nick(item)
        if not item:
            return f'{item} is not an item.'

        try:
            number = int(number)
        except ValueError:
            return f'{number} is not a valid number.'

        if not item.is_rune:
            return f'{items.get_attr(itemid)} is not a rune that can be crafted.'

        # Find out if user has the talisman
        rune_type = item.name.split(" ")[0]
        if not user.has_item_by_name(rune_type + " talisman"):
            return f'{items.get_attr(talismanid)} not found in inventory.'

        item_name = item.name
        runecrafting_level = user.rc_level
        runecraft_req = item.level
        player_potion = user.potion_slot.id if user.potion_slot else '0'

        if player_potion == 435:
            boosted_level = runecrafting_level + 3
        elif player_potion == 436:
            boosted_level = runecrafting_level + 6
        else:
            boosted_level = runecrafting_level

        if boosted_level < runecraft_req:
            return f'Error: {item_name} has a runecrafting requirement ({runecraft_req}) higher ' \
                   f'than your runecrafting level ({runecrafting_level})'

        if item.quest_req and not user.has_completed_quest(item.quest_req):
            return f'You do not have the required quest to craft this rune.'
        if not user.has_completed_quest(RUNE_MYSTERIES):
            return f'You do not know how to craft runes.'

        factor = 1 if user.has_completed_quest(ABYSS_QUEST) else 2
        bonus = 0
        for pouch in POUCHES:
            if user.has_item_by_item(pouch):
                bonus += pouch.pouch

        length = factor * math.ceil(number * 1.2 / (28.0 + bonus))
        ess_to_check = PURE_ESSENCE if pure else RUNE_ESSENCE
        if not user.has_item_amount_by_item(ess_to_check, number):
            return f'You do not have enough essence to craft this many runes.'

        rc_session = adv.format_line(6, user.id, adv.get_finish_time(length * 60), guildid, channelid,
                                     item.id, item_name, number, length, pure)
        adv.write(rc_session)
        out += f'You are now crafting {item.pluralize(number)} for {length} minutes.'
    else:
        out = adv.print_adventure(user.id)
        out += adv.print_on_adventure_error('runecrafting session')
    return out