def compare(item1, item2): """Prints a string comparing the stats of two given items.""" i1: Item = Item.find_by_name_or_nick(item1) i2: Item = Item.find_by_name_or_nick(item2) if not i1: return f'Error: {item1} does not exist.' if not i2: return f'Error: {item2} does not exist.' out = f':moneybag: __**COMPARE**__ :moneybag:\n'\ f'**{i1.name.title()} vs {i2.name.title()}:**\n\n'\ f'**Accuracy**: {i1.accuracy} vs {i2.accuracy} *({i1.accuracy - i2.accuracy})*\n' \ f'**Damage**: {i1.damage} vs {i2.damage} *({i1.damage - i2.damage})*\n' \ f'**Armour**: {i1.armour} vs {i2.armour} *({i1.armour - i2.armour})*\n' \ f'**Prayer Bonus**: {i1.prayer} vs {i2.prayer} *({i1.prayer - i2.prayer})*' return out
def eat(author, item): if item == 'none' or item == 'nothing': author.active_food = None author.save() return f'You are now eating nothing.' try: item = Item.find_food_by_name(item)[0] except IndexError: # No food matching what was sent in return f'You cannot eat {item.name}.' if item in Item.all_food(): author.active_food = item author.save() # TODO: Readd the pluaralization here per this comment # return f'You are now eating {items.add_plural(0, itemid)}!' return f'You are now eating {item.name}' else: return f'You cannot eat {item.name}.'
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
def print_item_stats(itemname: str): """Prints the stats of an item.""" item: Item = Item.find_by_name_or_nick(itemname) if not item: return f'Error: {item} is not an item.' name = item.name.title() value = '{:,}'.format(item.value) aliases = ', '.join(item.alias_strings) out = f'__**:moneybag: ITEMS :moneybag:**__\n' out += f'**Name**: {name}\n' if len(aliases) > 0: out += f'**Aliases**: {aliases}\n' out += f'**Value**: {value} gp\n' if item.slot > 0: damage = item.damage if item.damage else 0 accuracy = item.accuracy if item.accuracy else 0 prayer = item.prayer if item.prayer else 0 level = item.level if item.level else 1 armour = item.armour if item.armour else 0 out += f'\n**Damage**: {damage}\n' out += f'**Accuracy**: {accuracy}\n' out += f'**Armour**: {armour}\n' out += f'**Prayer Bonus**: {prayer}\n' out += f'**Slot**: {SLOTS[str(item.slot)].title()}\n' out += f'**Combat Requirement**: {level}\n' if item.is_gatherable: xp = item.xp level = item.level if item.level else 1 out += f'**Gather Requirement**: {level}\n' out += f'**xp**: {xp}\n' out += "\n**Drop Sources:**" dropping_monsters = item.monsterloot_set.all().order_by('rarity') ml: MonsterLoot for ml in dropping_monsters: if ml.min_amount == ml.max_amount: amt = ml.min_amount else: amt = "%d-%d" % (ml.min_amount, ml.max_amount) out += f'\n{ml.monster.name.title()} _(amount: {amt}, rarity: {ml.rarity_str})_' out += clue_helpers.print_item_from_lootable(item) return out
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
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)]}!'
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)]}!'
def print_pets(person): """Prints a formatted list of pets a user has.""" user_pets = [item.item for item in person.get_pets()] all_pets = Item.all_pets() pets_header = f':cat: __**PETS**__ :dog:\n' messages = [] out = pets_header for pet in all_pets: if pet in user_pets: out += f"**{pet.name.title()}**\n" else: out += f'{pet.name.title()}\n' if len(out) > 1900: messages.append(out) out = pets_header out += f'{len(user_pets)}/{len(all_pets)}' messages.append(out) return messages
def print_recipe(user, recipe): """Prints details related to a particular recipe.""" created_item = Item.find_by_name_or_nick(recipe) recipe = Recipe.objects.filter(creates=created_item) if not recipe: return f'Error: cannot find recipe that crafts {recipe}.' recipe = recipe[0] out = f'{CRAFT_HEADER}'\ f'**Name**: {created_item.name.title()}\n'\ f'**Artisan Requirement**: {recipe.level_requirement}\n'\ f'**XP Per Item**: {created_item.xp}\n'\ f'**Inputs**:\n' item_requirements = RecipeRequirement.objects.filter(recipe=recipe) for requirement in item_requirements: if user.has_item_by_item(requirement.item): out += f'~~{requirement.item.pluralize(requirement.amount)}~~\n' else: out += f'{requirement.item.pluralize(requirement.amount)}\n' return out
def sell(userid, item, number): """Sells (a given amount) of an item from a user's inventory.""" user = User.objects.get(id=userid) item: Item = Item.find_by_name_or_nick(item) if not item: return f'Error: {item} is not an item.' try: number = int(number) except ValueError: return f'Error: {number} is not a number.' item_name = item.name if user.has_item_amount_by_item(item, number): value = item.value coin = Item.objects.get(name="coins") user.update_inventory(Counter({coin: value*number})) user.update_inventory(Counter({item: number}), remove=True) value_formatted = '{:,}'.format(value * number) return f'{number} {item_name} sold for {value_formatted} coins!' else: return f'Error: {item_name} not in inventory or you do not have at least {number} in your inventory.'
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
def buy(userid, item, number): """Buys (a given amount) of an item and places it in the user's inventory.""" user = User.objects.get(id=userid) item: Item = Item.find_by_name_or_nick(item) if not item: return f'Error: {item} is not an item.' try: number = int(number) except ValueError: return f'Error: {number} is not a number.' item_name = item.name if item_in_shop(item.id): items = open_shop() quest_id = int(items[str(item.id)]) quest_req = None if quest_id: quest_req = Quest.objects.get(id=quest_id) if not quest_id or user.has_completed_quest(quest_req): value = item.value cost = 4 * number * value coin = Item.objects.get(name="coins") if user.has_item_amount_by_item(coin, cost): user.update_inventory(Counter({coin: cost}), remove=True) user.update_inventory(Counter({item: number})) 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 available in shop.'
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
def start_gather(guildid, channelid, user: User, itemname, length=-1, number=-1): """Starts a gathering session.""" from miniscape import adventures as adv out = '' userid = user.id if not adv.is_on_adventure(userid): item: Item = Item.find_by_name_or_nick(itemname) if not item: return f'Error: {item} is not an item.' try: length = int(length) number = int(number) except ValueError: return f'Error: {length} is not a valid length of time.' if not item.is_gatherable: return f'Error: you cannot gather item {ite.name}.' quest_req = item.quest_req if quest_req and quest_req not in user.completed_quests_list: return f'Error: You do not have the required quest to gather this item.' item_name = item.name gather_level = user.gather_level gather_requirement = item.level player_potion = user.potion_slot.id if user.potion_slot else '0' if player_potion == 435: boosted_level = gather_level + 3 elif player_potion == 436: boosted_level = gather_level + 6 else: boosted_level = gather_level if boosted_level < gather_requirement: return f'Error: {item_name} has a gathering requirement ({gather_requirement}) higher ' \ f'than your gathering level ({gather_level})' # Adjust the number approppriately if number > 1000 and gather_level == 99: number = 1000 if number > 500 and gather_level < 99: number = 500 if length > 180: length = 180 if int(number) < 0: number = calc_number(user,item, length * 60) if number > 500: number = 500 elif int(length) < 0: length = math.floor(calc_length(user, item, number)[1] / 60) else: return 'Error: argument missing (number or kill length).' gather = adv.format_line(3, userid, adv.get_finish_time(length * 60), guildid, channelid, item.id, item_name, number, length) adv.write(gather) out += f'You are now gathering {item.pluralize(number)} for {length} minutes.' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('gathering') return out