def start_quest(userid, questid): """Assigns a user a slayer task provided they are not in the middle of another adventure.""" out = QUEST_HEADER if not adv.is_on_adventure(userid): try: name = get_attr(questid) except KeyError: return f"Error: 1uest number {questid} does not refer to any quest." if has_quest_reqs(userid, questid): if int(questid) not in set(users.get_completed_quests(userid)): if has_item_reqs(userid, questid): required_items = get_attr(questid, key=ITEM_REQ_KEY) loot = [] for item in required_items: loot.extend(required_items[item] * [item]) users.update_inventory(userid, loot, remove=True) chance = calc_chance(userid, questid) quest_length = calc_length(userid, questid) quest = adv.format_line(2, userid, adv.get_finish_time(quest_length), questid, chance) adv.write(quest) out += print_quest(questid, quest_length, chance) else: return "Error: you do not have all the required items to start this quest." else: return "Error: you have already done this quest." else: return "Error: you have not completed the required quests to do this quest." else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('quest') return out
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.'
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 print_list(userid): """Lists quests a user can do at the moment.""" out = f'{QUEST_HEADER}' for questid in list(QUESTS.keys()): if has_quest_reqs(userid, questid): if int(questid) in set(users.get_completed_quests(userid)): out += f'~~**{questid}**. {get_attr(questid)}~~\n' else: out += f'**{questid}**. {get_attr(questid)}\n' out += f'\n**Quests Completed**: {len(users.get_completed_quests(userid))}/{len(QUESTS.keys())}\n' out += 'Type `~quest [quest number]` to see more information about a quest.' return out
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
def get_kill(userid, monster, length=-1, number=-1): """Lets the user start killing monsters..""" out = f'{SLAYER_HEADER}' if not adv.is_on_adventure(userid): try: monsterid = mon.find_by_name(monster) length = int(length) number = int(number) except KeyError: return f'Error: {monster} is not a monster.' except ValueError: return f'Error: {length} is not a valid length of time.' completed_quests = users.get_completed_quests(userid) quest_req = mon.get_attr(monsterid, key=mon.QUEST_REQ_KEY) if not {quest_req}.issubset(completed_quests) and quest_req != 0: return f'Error: you do not have the required quests to kill this monster.' monster_name = mon.get_attr(monsterid) slayer_level = users.xp_to_level(users.read_user(userid, key=users.SLAYER_XP_KEY)) slayer_requirement = mon.get_attr(monsterid, key=mon.SLAYER_REQ_KEY) if slayer_level < slayer_requirement: return f'Error: {monster_name} has a slayer requirement ({slayer_requirement}) higher ' \ f'than your slayer level ({slayer_level})' if number > 1000 and slayer_level == 99: number = 1000 if number > 500 and slayer_level < 99: number = 500 if length > 180: length = 180 if int(number) < 0: number = calc_number(userid, monsterid, (length + 1) * 60) - 1 if number > 1000 and slayer_level == 99: number = 1000 if number > 500 and slayer_level < 99: number = 500 elif int(length) < 0: length = math.floor(calc_length(userid, monsterid, number)[1] / 60) else: return 'Error: argument missing (number or kill length).' grind = adv.format_line(1, userid, adv.get_finish_time(length * 60), monsterid, monster_name, number, length) adv.write(grind) out += f'You are now killing {mon.add_plural(number, monsterid, with_zero=True)} for {length} minutes. ' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('kill') return out
def print_list(userid): """Prints a list of the recipes a user can use.""" completed_quests = set(users.get_completed_quests(userid)) messages = [] out = f'{CRAFT_HEADER}' for itemid in list(RECIPES.keys()): quest_reqs = get_attr(itemid, key=QUEST_REQ_KEY) if set(quest_reqs).issubset(completed_quests): out += f'**{items.get_attr(itemid)}** *(level {get_attr(itemid, key=LEVEL_REQ_KEY)})*\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_reaper_task(userid): """Assigns a user a reaper task provided they are not in the middle of another adventure.""" out = SLAYER_HEADER if users.get_level(userid, key=users.SLAYER_XP_KEY) < 50: out += "Your slayer level is too low to start a reaper task. You need at least 50 slayer." return out print(users.read_user(userid, key=users.LAST_REAPER_KEY)) if datetime.datetime.fromtimestamp(users.read_user(userid, key=users.LAST_REAPER_KEY)).date() \ >= datetime.date.today(): out += 'You have already done a reaper task today. Please come back tomorrow for another one.' return out if not adv.is_on_adventure(userid): completed_quests = set(users.get_completed_quests(userid)) for _ in range(1000): monsterid = mon.get_random(slayer_level=users.xp_to_level(users.read_user(userid, key=users.SLAYER_XP_KEY))) num_to_kill = mon.get_task_length(monsterid) base_time, task_length = calc_length(userid, monsterid, num_to_kill) chance = calc_chance(userid, monsterid, num_to_kill) # print(f'{monsterid} {task_length/base_time} {chance}') if 0.25 <= task_length / base_time <= 2 and chance >= 20 \ and mon.get_attr(monsterid, key=mon.BOSS_KEY) is True\ and ({mon.get_attr(monsterid, key=mon.QUEST_REQ_KEY)}.issubset(completed_quests) or mon.get_attr(monsterid, key=mon.QUEST_REQ_KEY) == 0): break else: return "Error: gear too low to fight any monsters. Please equip some better gear and try again. " \ "If you are new, type `~starter` to get a bronze kit." monster_name = mon.get_attr(monsterid) cb_perk = False if users.read_user(userid, key=users.COMBAT_XP_KEY) == 99 and random.randint(1, 20) == 1: task_length *= 0.7 cb_perk = True task = adv.format_line(5, userid, adv.get_finish_time(task_length), monsterid, monster_name, num_to_kill, chance) adv.write(task) users.update_user(userid, datetime.date.today(), key=users.LAST_REAPER_KEY) out += print_task(userid, reaper=True) if cb_perk is True: out += 'Your time has been reduced by 30% due to your combat perk!' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('reaper task') return out
def calc_length(userid, difficulty): """Calculates the time it takes to do a clue scroll.""" quests_completed = len(users.get_completed_quests(userid)) num_of_quests = len(list(quests.QUESTS.keys())) player_damage = users.get_equipment_stats( users.read_user(userid, key=users.EQUIPMENT_KEY))[0] + 1 quest_multiplier = min((6 - difficulty) * quests_completed / num_of_quests, 1) base_time = 450 * difficulty time = base_time / (quest_multiplier * player_damage / 200) if time / base_time < 0.8: time = 0.8 * base_time return round(time)
def print_shop(userid): """Prints the shop.""" items = open_shop() out = SHOP_HEADER messages = [] for itemid in list(items.keys()): if int(items[itemid]) in set( users.get_completed_quests(userid)) or items[itemid] == '0': name = get_attr(itemid) price = '{:,}'.format(4 * get_attr(itemid, key=VALUE_KEY)) out += f'**{name.title()}**: {price} coins\n' if len(out) > 1800: messages.append(out) out = SHOP_HEADER messages.append(out) return messages
def print_shop(userid): """Prints the shop.""" items = open_shop() header = '__**:moneybag: SHOP :moneybag:**__\n' messages = [] out = f'{header}' for itemid in list(items.keys()): if int(items[itemid]) in set( users.get_completed_quests(userid)) or items[itemid] == '0': name = get_attr(itemid) price = '{:,}'.format(4 * get_attr(itemid, key=VALUE_KEY)) out += f'**{name.title()}**: G${price}\n' if len(out) > 1800: messages.append(out) out = f'{header}' messages.append(out) return messages
def get_task(userid): """Assigns a user a slayer task provided they are not in the middle of another adventure.""" out = SLAYER_HEADER if not adv.is_on_adventure(userid): user_level = users.xp_to_level(users.read_user(userid, key=users.COMBAT_XP_KEY)) completed_quests = set(users.get_completed_quests(userid)) equipment = users.read_user(userid, key=users.EQUIPMENT_KEY) for _ in range(1000): monsterid = mon.get_random(slayer_level=users.xp_to_level(users.read_user(userid, key=users.SLAYER_XP_KEY))) num_to_kill = mon.get_task_length(monsterid) base_time, task_length = calc_length(userid, monsterid, num_to_kill) chance = calc_chance(userid, monsterid, num_to_kill) mon_level = mon.get_attr(monsterid, key=mon.LEVEL_KEY) # print(f'{monsterid} {task_length/base_time} {chance}') if 0.25 <= task_length / base_time <= 2 and chance >= 20 and mon_level / user_level >= 0.8\ and mon.get_attr(monsterid, key=mon.SLAYER_KEY) is True\ and ({mon.get_attr(monsterid, key=mon.QUEST_REQ_KEY)}.issubset(completed_quests) or mon.get_attr(monsterid, key=mon.QUEST_REQ_KEY) == 0): break else: return "Error: gear too low to fight any monsters. Please equip some better gear and try again. " \ "If you are new, type `~starter` to get a bronze kit." cb_perk = False if users.read_user(userid, key=users.COMBAT_XP_KEY) == 99 and random.randint(1, 20) == 1: task_length *= 0.7 cb_perk = True monster_name = mon.get_attr(monsterid) task = adv.format_line(0, userid, adv.get_finish_time(task_length), monsterid, monster_name, num_to_kill, chance) adv.write(task) out += print_task(userid) if cb_perk is True: out += 'Your time has been reduced by 30% due to your combat perk!' else: out = adv.print_adventure(userid) out += adv.print_on_adventure_error('task') return out
def has_quest_reqs(userid, questid): """Checks if a user can do a quest based on based on previous quest requirements.""" quest_reqs = set(get_attr(questid, key=QUEST_REQ_KEY)) user_quests = set(users.get_completed_quests(userid)) return quest_reqs.issubset(user_quests)