def print_inventory(userid, search): """Prints a list of a user's inventory into discord message-sized chunks.""" inventory = read_user(userid) header = ':moneybag: __**INVENTORY**__ :moneybag:\n' messages = [] out = header for itemid in list(inventory.keys()): name = items.get_attr(itemid) if search != '': if search not in name.lower(): continue value = items.get_attr(itemid, key=items.VALUE_KEY) value_formatted = '{:,}'.format(value) item_total_value = int(inventory[itemid]) * value item_total_value_formatted = '{:,}'.format(item_total_value) if inventory[itemid] > 0: out += f'**{items.get_attr(itemid).title()}**: {inventory[itemid]}. ' \ f'*(value: {item_total_value_formatted}, {value_formatted} ea.)*\n' if len(out) > 1800: messages.append(out) out = header total_value = '{:,}'.format(get_value_of_inventory(inventory)) out += f'*Total value: {total_value}*' messages.append(out) return messages
def calc_number(userid, itemid, time): """Calculates the number of items that can be gathered in a given time period.""" gather_level = users.xp_to_level( users.read_user(userid, key=users.GATHER_XP_KEY)) item_xp = items.get_attr(itemid, key=items.XP_KEY) item_level = items.get_attr(itemid, key=items.LEVEL_KEY) equipment = users.read_user(userid, key=users.EQUIPMENT_KEY) if items.TREE_KEY: if int(equipment['13']) > -1: item_multiplier = 2 - ( items.get_attr(equipment['13'], key=items.LEVEL_KEY) / 100) else: item_multiplier = 10 elif items.ROCK_KEY: if int(equipment['14']) > -1: item_multiplier = 2 - ( items.get_attr(equipment['14'], key=items.LEVEL_KEY) / 100) else: item_multiplier = 10 else: item_multiplier = 2 time_multiplier = gather_level / item_level number = math.floor(time * time_multiplier / (item_xp * item_multiplier * ((100 - item_level) / 200))) return number
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!'
def equip_item(userid, item): """Takes an item out of a user's inventory and places it into their equipment.""" try: itemid = items.find_by_name(item) except KeyError: return f'Error: {item} does not exist.' item_level = items.get_attr(itemid, key=items.LEVEL_KEY) user_cb_level = xp_to_level(read_user(userid, key=COMBAT_XP_KEY)) if user_cb_level >= item_level: item_name = items.get_attr(itemid) if item_in_inventory(userid, itemid): slot = str(items.get_attr(itemid, key=items.SLOT_KEY)) if int(slot) > 0: equipment = read_user(userid, key=EQUIPMENT_KEY) if slot not in equipment.keys() or equipment[slot] == -1: equipment[slot] = itemid else: update_inventory(userid, [equipment[slot]]) equipment[slot] = itemid update_inventory(userid, [itemid], remove=True) update_user(userid, equipment, EQUIPMENT_KEY) return f'{item_name} equipped to {SLOTS[slot]}!' else: return f'Error: {item_name} cannot be equipped.' else: return f'Error: {item_name} not in inventory.' else: return f'Error: Insufficient level to equip item ({item_level}). Your current combat level is {user_cb_level}.'
def start_gather(userid, item, length=-1, number=-1): """Starts a gathering session.""" out = '' if not adv.is_on_adventure(userid): try: itemid = items.find_by_name(item) length = int(length) number = int(number) except KeyError: return f'Error: {item} is not an item.' except ValueError: return f'Error: {length} is not a valid length of time.' if not items.get_attr(itemid, key=items.GATHER_KEY): return f'Error: you cannot gather item {items.get_attr(itemid)}.' item_name = items.get_attr(itemid) gather_level = users.xp_to_level( users.read_user(userid, key=users.GATHER_XP_KEY)) gather_requirement = items.get_attr(itemid, key=items.LEVEL_KEY) player_potion = users.read_user(userid, key=users.EQUIPMENT_KEY)['15'] if player_potion == '435': boosted_level = gather_level + 3 if 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})' quest_req = items.get_attr(itemid, key=items.QUEST_KEY) if quest_req not in set( users.get_completed_quests(userid)) and quest_req > 0: return f'Error: You do not have the required quest to gather this item.' 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(userid, itemid, length * 60) if number > 500: number = 500 elif int(length) < 0: length = math.floor(calc_length(userid, itemid, number)[1] / 60) else: return 'Error: argument missing (number or kill length).' gather = adv.format_line(3, userid, adv.get_finish_time(length * 60), itemid, item_name, number, length) adv.write(gather) out += f'You are now gathering {items.add_plural(number, itemid)} for {length} minutes.' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('gathering') return out
def calc_number(userid, itemid, time): """Calculates the number of items that can be gathered in a given time period.""" gather_level = users.xp_to_level(users.read_user(userid, key=users.GATHER_XP_KEY)) item_xp = items.get_attr(itemid, key=items.XP_KEY) item_level = items.get_attr(itemid, key=items.LEVEL_KEY) number = math.floor((gather_level * time) / (120 * item_xp * item_level)) return number
def find_by_name(name, cook=False): """Finds an Recipe's ID from its name.""" for itemid in list(RECIPES.keys()): if name in items.get_attr(itemid): cookable = items.get_attr(itemid, key=items.COOK_KEY) if (cook and not cookable) or (not cook and cookable): raise TypeError return itemid else: raise KeyError
def calc_length(userid, itemid, number): """Calculates the length of gathering a number of an item.""" gather_level = users.xp_to_level(users.read_user(userid, key=users.GATHER_XP_KEY)) item_xp = items.get_attr(itemid, key=items.XP_KEY) item_level = items.get_attr(itemid, key=items.LEVEL_KEY) time_multiplier = gather_level / item_level base_time = math.floor(number * item_xp / 5) time = round(base_time / time_multiplier) return base_time, time
def get_equipment_stats(equipment): """Gets the total combat stats for the current equipment worn by a user.""" damage = 0 accuracy = 0 armour = 0 for itemid in equipment.values(): try: damage += items.get_attr(itemid, key=items.DAMAGE_KEY) accuracy += items.get_attr(itemid, key=items.ACCURACY_KEY) armour += items.get_attr(itemid, key=items.ARMOUR_KEY) except KeyError: pass return damage, accuracy, armour
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
def find_by_name(name): """Finds an Recipe's ID from its name.""" for itemid in list(RECIPES.keys()): if name in items.get_attr(itemid): return itemid else: raise KeyError
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
def calc_burn(userid, itemid): """Calculates the burn chance for a given food.""" cook_level = users.read_user(userid, key=users.COOK_XP_KEY) cook_req = items.get_attr(itemid, key=items.COOK_KEY) equipment = users.read_user(userid, key=users.EQUIPMENT_KEY) c = 10 if equipment['9'] == '493' else 0 chance = max(100 * ((cook_level - cook_req + c) / 20), 20) return 100 - min(100, chance)
def start_gather(userid, item, length=-1, number=-1): """Starts a gathering session.""" out = '' if not adv.is_on_adventure(userid): try: itemid = items.find_by_name(item) length = int(length) number = int(number) except KeyError: return f'Error: {item} is not an item.' except ValueError: return f'Error: {length} is not a valid length of time.' if not items.get_attr(itemid, key=items.GATHER_KEY): return f'Error: you cannot gather item {items.get_attr(itemid)}.' item_name = items.get_attr(itemid) gather_level = users.xp_to_level(users.read_user(userid, key=users.GATHER_XP_KEY)) gather_requirement = items.get_attr(itemid, key=items.LEVEL_KEY) if gather_level < gather_requirement: return f'Error: {item_name} has a gathering requirement ({gather_requirement}) higher ' \ f'than your gathering level ({gather_level})' if number > 500: number = 500 if length > 180: length = 180 if int(number) < 0: number = calc_number(userid, itemid, length * 60) if number > 500: number = 500 elif int(length) < 0: length = math.floor(calc_length(userid, itemid, number)[1] / 60) else: return 'Error: argument missing (number or kill length).' gather = adv.format_line(3, userid, adv.get_finish_time(length * 60), itemid, item_name, number, length) adv.write(gather) out += f'You are now gathering {number} {items.add_plural(itemid)} for {length} minutes.' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('gathering') return out
def clear_inventory(userid, under=None): """Removes all items (with value) in an account's inventory.""" if under is not None: max_sell = int(under) else: max_sell = 2147483647 inventory = read_user(userid, ITEMS_KEY) for itemid in list(inventory.keys()): value = items.get_attr(itemid, key=items.VALUE_KEY) if inventory[itemid] > 0 and 0 < value < max_sell: inventory[itemid] = 0 update_user(userid, inventory, key=ITEMS_KEY)
def get_value_of_inventory(inventory, under=None): """Gets the total value of a user's inventory.""" if under is not None: max_value = int(under) else: max_value = 2147483647 total_value = 0 for item in list(inventory.keys()): value = items.get_attr(item, key=items.VALUE_KEY) if value < max_value: total_value += int(inventory[item]) * value return total_value
def calc_length(userid, itemid, number): """Calculates the length of gathering a number of an item.""" gather_level = users.xp_to_level( users.read_user(userid, key=users.GATHER_XP_KEY)) item_xp = items.get_attr(itemid, key=items.XP_KEY) item_level = items.get_attr(itemid, key=items.LEVEL_KEY) equipment = users.read_user(userid, key=users.EQUIPMENT_KEY) if items.get_attr(itemid, key=items.TREE_KEY): if int(equipment['13']) > -1: item_multiplier = 2 - ( items.get_attr(equipment['13'], key=items.LEVEL_KEY) / 100) else: item_multiplier = 10 elif items.get_attr(itemid, key=items.ROCK_KEY): if int(equipment['14']) > -1: item_multiplier = 2 - ( items.get_attr(equipment['14'], key=items.LEVEL_KEY) / 100) else: item_multiplier = 10 else: item_multiplier = 2 time_multiplier = gather_level / item_level base_time = math.floor(number * item_xp * (100 - item_level) / 200) time = round(item_multiplier * base_time / time_multiplier) return base_time, time
def print_monster(monster): """Prints information related to a monster.""" try: monsterid = find_by_name(monster.lower()) except KeyError: return [f'Error: {monster} is not a monster.'] messages = [] aliases = ', '.join(get_attr(monsterid, key=NICK_KEY)) out = f'__**:skull_crossbones: BESTIARY :skull_crossbones:**__\n'\ f'**Name**: {MONSTERS[monsterid][NAME_KEY].title()}\n' if len(aliases) > 0: out += f'**Aliases**: {aliases}\n' slayer_req = get_attr(monsterid, key=SLAYER_REQ_KEY) if slayer_req > 1: out += f'**Slayer Requirement**: {slayer_req}\n' out += f'**Level**: {MONSTERS[monsterid][LEVEL_KEY]}\n'\ f'**Accuracy**: {MONSTERS[monsterid][ACCURACY_KEY]}\n'\ f'**Damage**: {MONSTERS[monsterid][DAMAGE_KEY]}\n'\ f'**Armour**: {MONSTERS[monsterid][ARMOUR_KEY]}\n'\ f'**XP**: {MONSTERS[monsterid][XP_KEY]}\n\n'\ f'**Loot Table**:\n' loottable = get_loot_table(monsterid) for item in list(loottable.keys()): itemname = items.get_attr(item) itemmin = int(loottable[item]['min']) itemmax = int(loottable[item]['max']) rarity = loottable[item]['rarity'] for key in list(RARITY_NAMES.keys()): if key <= rarity: name = key else: break out += f"{itemname} *(amount: " if itemmin == itemmax: out += f'{itemmin}, ' else: out += f"{itemmin}-{itemmax}, " out += f"rarity: {RARITY_NAMES[name]})*\n" if len(out) >= 1800: messages.append(out) out = f'__**:skull_crossbones: BESTIARY :skull_crossbones:**__\n' messages.append(out) return messages
def unequip_item(userid, item): """Takes an item out of a user's equipment and places it into their inventory.""" try: itemid = items.find_by_name(item) except KeyError: return f'Error: {item} does not exist.' item_name = items.get_attr(itemid) equipment = read_user(userid, key=EQUIPMENT_KEY) if itemid in equipment.values(): slot = str(items.get_attr(itemid, key=items.SLOT_KEY)) if int(slot) > 0: equipment = read_user(userid, key=EQUIPMENT_KEY) if equipment[slot] == -1: return f'{item_name} is not equipped in {SLOTS[str(slot)]}.' update_inventory(userid, [itemid]) equipment[slot] = -1 update_user(userid, equipment, EQUIPMENT_KEY) return f'{item_name} unequipped from {SLOTS[str(slot)]}!' else: return f'Error: {item_name} cannot be unequipped.' else: return f'You do not have {item_name} equipped.'
def print_inventory(person, search): """Prints a list of a user's inventory into discord message-sized chunks.""" inventory = read_user(person.id) if person.nick is None: name = person.name else: name = person.nick header = f":moneybag: __**{name.upper()}'S INVENTORY**__ :moneybag:\n" messages = [] out = header locked_items = read_user(person.id, key=LOCKED_ITEMS_KEY) sorted_items = [] for itemid in inventory.keys(): sorted_items.append((items.get_attr(itemid), itemid)) for name, itemid in sorted(sorted_items, key=lambda tup: tup[0]): # name = items.get_attr(itemid) if search != '': if search not in name.lower(): continue value = items.get_attr(itemid, key=items.VALUE_KEY) value_formatted = '{:,}'.format(value) item_total_value = int(inventory[itemid]) * value item_total_value_formatted = '{:,}'.format(item_total_value) if inventory[itemid] > 0: out += f'**{items.get_attr(itemid).title()} ' if itemid in locked_items: out += f'(:lock:)' out += f'**: {inventory[itemid]}. *(value: {item_total_value_formatted}, {value_formatted} ea.)*\n' if len(out) > 1800: messages.append(out) out = header total_value = '{:,}'.format(get_value_of_inventory(person.id, add_locked=True)) out += f'*Total value: {total_value}*\n' messages.append(out) return messages
def unlock_item(userid, item): """Unlocks an item, allowing it to be sold again.""" try: itemid = items.find_by_name(item) except KeyError: return f'No item with name {item} found.' item_name = items.get_attr(itemid) locked_items = read_user(userid, key=LOCKED_ITEMS_KEY) if itemid not in locked_items: return f'{item_name} is already unlocked.' locked_items.remove(itemid) update_user(userid, locked_items, key=LOCKED_ITEMS_KEY) return f'{item_name} has been unlocked!'
def lock_item(userid, item): """Locks an item from being sold accidentally.""" try: itemid = items.find_by_name(item) except KeyError: return f'No item with name {item} found.' item_name = items.get_attr(itemid) locked_items = read_user(userid, key=LOCKED_ITEMS_KEY) if itemid in locked_items: return f'{item_name} is already locked.' locked_items.append(itemid) update_user(userid, locked_items, key=LOCKED_ITEMS_KEY) return f'{item_name} has been locked!'
def get_gather(person, *args): try: itemid, item_name, number, length = args[0] except ValueError as e: print(e) raise ValueError loot = int(number) * [itemid] xp = int(number) * items.get_attr(itemid, key=items.XP_KEY) users.update_inventory(person.id, loot) users.update_user(person.id, xp, key=users.GATHER_XP_KEY) xp_formatted = '{:,}'.format(xp) out = f'{GATHER_HEADER}' \ f'{person.mention}, you gathering session has finished! You have gathered ' \ f'{number} {items.add_plural(itemid)} and have gained {xp_formatted} gathering xp!' return out
def get_value_of_inventory(userid, inventory=None, under=None, add_locked=False): """Gets the total value of a user's inventory.""" if inventory is None: inventory = read_user(userid) if under is not None: max_value = int(under) else: max_value = 999999999999 total_value = 0 locked_items = set(read_user(userid, key=LOCKED_ITEMS_KEY)) for item in list(inventory.keys()): value = items.get_attr(item, key=items.VALUE_KEY) if value < max_value: if item not in locked_items or add_locked: total_value += int(inventory[item]) * value return total_value
def print_list(userid, search): """Prints a list of the recipes a user can use.""" # completed_quests = set(users.get_completed_quests(userid)) messages = [] out = f'{CRAFT_HEADER}' recipe_list = [] for itemid in list(RECIPES.keys()): name = items.get_attr(itemid) level = get_attr(itemid, key=ARTISAN_REQ_KEY) recipe_list.append((level, name)) for recipe in sorted(recipe_list): if search in recipe[1]: out += f'**{recipe[1].title()}** *(level {recipe[0]})*\n' if len(out) > 1800: messages.append(out) out = f'{CRAFT_HEADER}' out += 'Type `~recipes info [item]` to get more info about how to craft a particular item.' messages.append(out) return messages
def get_gather(person, *args): try: itemid, item_name, number, length = args[0] except ValueError as e: print(e) raise ValueError loot = int(number) * [itemid] xp = XP_FACTOR * int(number) * items.get_attr(itemid, key=items.XP_KEY) users.update_inventory(person.id, loot) gather_level_before = users.xp_to_level( users.read_user(person.id, users.GATHER_XP_KEY)) users.update_user(person.id, xp, key=users.GATHER_XP_KEY) gather_level_after = users.xp_to_level( users.read_user(person.id, users.GATHER_XP_KEY)) xp_formatted = '{:,}'.format(xp) out = f'{GATHER_HEADER}' \ f'{person.mention}, your gathering session has finished! You have gathered ' \ f'{items.add_plural(number, itemid)} and have gained {xp_formatted} gathering xp! ' if gather_level_after > gather_level_before: out += f'In addition, you have gained {gather_level_after - gather_level_before} gathering levels!' users.remove_potion(person.id) return out