def get_result(person, *args): """Determines the success and loot of a slayer task.""" try: monsterid, monster_name, num_to_kill, chance = args[0] except ValueError as e: print(e) raise ValueError out = '' if adv.is_success(calc_chance(person.id, monsterid)): loot = mon.get_loot(monsterid, int(num_to_kill)) users.update_inventory(person.id, loot) out += print_loot(loot, person, monster_name, num_to_kill) xp_gained = mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) users.update_user(person.id, xp_gained, users.SLAYER_XP_KEY) users.update_user(person.id, round(0.7 * xp_gained), users.COMBAT_XP_KEY) slayer_xp_formatted = '{:,}'.format(xp_gained) combat_xp_formatted = '{:,}'.format(round(0.7 * xp_gained)) out += f'\nYou have also gained {slayer_xp_formatted} slayer xp and {combat_xp_formatted} combat xp.' else: xp_gained = round(mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) / 4) users.update_user(person.id, xp_gained, users.SLAYER_XP_KEY) users.update_user(person.id, round(0.7 * xp_gained), users.COMBAT_XP_KEY) slayer_xp_formatted = '{:,}'.format(xp_gained) combat_xp_formatted = '{:,}'.format(round(0.7 * xp_gained)) out += f'{person.mention}, your slayer task of {num_to_kill} {mon.add_plural(monsterid)} has failed.\n'\ f'You have received {slayer_xp_formatted} slayer xp and {combat_xp_formatted} combat xp.' return out
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
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)
def get_kill_result(person, *args): """Determines the loot of a monster grind.""" try: monsterid, monster_name, num_to_kill, length = args[0] except ValueError as e: print(e) raise ValueError out = '' users.add_counter(person.id, monsterid, num_to_kill) if mon.get_attr(monsterid, key=mon.SLAYER_KEY): factor = 0.75 else: factor = 1 factor *= items.get_luck_factor(person.id) loot = mon.get_loot(monsterid, int(num_to_kill), factor=factor) users.update_inventory(person.id, loot) out += print_loot(loot, person, monster_name, num_to_kill) xp_gained = mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) cb_level_before = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) users.update_user(person.id, xp_gained, users.COMBAT_XP_KEY) cb_level_after = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) combat_xp_formatted = '{:,}'.format(xp_gained) out += f'\nYou have also gained {combat_xp_formatted} combat xp' if cb_level_after > cb_level_before: out += f' and {cb_level_after - cb_level_before} combat levels' out += '.' users.remove_potion(person.id) return out
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 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 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
def get_reaper_result(person, *args): """Determines the success and loot of a reaper task.""" try: monsterid, monster_name, num_to_kill, chance = args[0] except ValueError as e: print(e) raise ValueError out = '' users.add_counter(person.id, monsterid, num_to_kill) if adv.is_success(calc_chance(person.id, monsterid, num_to_kill)): users.remove_potion(person.id) factor = 0.7 * items.get_luck_factor(person.id) loot = mon.get_loot(monsterid, int(num_to_kill), factor=factor) loot['291'] = 1 users.update_inventory(person.id, loot) out += print_loot(loot, person, monster_name, num_to_kill) xp_gained = XP_FACTOR * mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) cb_level_before = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) slay_level_before = users.xp_to_level(users.read_user(person.id, users.SLAYER_XP_KEY)) users.update_user(person.id, xp_gained, users.SLAYER_XP_KEY) users.update_user(person.id, round(0.7 * xp_gained), users.COMBAT_XP_KEY) cb_level_after = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) slay_level_after = users.xp_to_level(users.read_user(person.id, users.SLAYER_XP_KEY)) slayer_xp_formatted = '{:,}'.format(xp_gained) combat_xp_formatted = '{:,}'.format(round(0.7 * xp_gained)) out += f'\nYou have also gained {slayer_xp_formatted} slayer xp and {combat_xp_formatted} combat xp. ' if cb_level_after > cb_level_before: out += f'In addition, you have gained {cb_level_after - cb_level_before} combat levels. ' if slay_level_after > slay_level_before: out += f'Also, as well, you have gained {slay_level_after - slay_level_before} slayer levels. ' else: users.remove_potion(person.id) factor = int(chance)/170 * items.get_luck_factor(person.id) loot = mon.get_loot(monsterid, int(num_to_kill), factor=factor) loot.append('291') users.update_inventory(person.id, loot) out += print_loot(loot, person, monster_name, num_to_kill) xp_gained = round(XP_FACTOR * mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) * factor) cb_level_before = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) slay_level_before = users.xp_to_level(users.read_user(person.id, users.SLAYER_XP_KEY)) users.update_user(person.id, xp_gained, users.SLAYER_XP_KEY) users.update_user(person.id, round(0.7 * xp_gained), users.COMBAT_XP_KEY) cb_level_after = users.xp_to_level(users.read_user(person.id, users.COMBAT_XP_KEY)) slay_level_after = users.xp_to_level(users.read_user(person.id, users.SLAYER_XP_KEY)) slayer_xp_formatted = '{:,}'.format(xp_gained) combat_xp_formatted = '{:,}'.format(round(0.7 * xp_gained)) out += f'\nYou have received lower loot and experience because you have died.'\ f'\nYou have received {slayer_xp_formatted} slayer xp and {combat_xp_formatted} combat xp. ' if cb_level_after > cb_level_before: out += f'Also, you have gained {cb_level_after - cb_level_before} combat levels. ' if slay_level_after > slay_level_before: out += f'In addition, you have gained {slay_level_after - slay_level_before} slayer levels. ' return out
async def starter_gear(self, ctx): """Gives the user a set of bronze armour.""" if ctx.channel.id == SHOP_CHANNEL or ctx.channel.id == COMBAT_CHANNEL: if users.read_user(ctx.author.id, key=users.COMBAT_XP_KEY) == 0: users.update_inventory(ctx.author.id, [63, 66, 69, 70]) await ctx.send( f'Bronze set given to {ctx.author.name}! You can see your items by typing `~inventory` ' f'and equip them by typing `~me equip [item]`. You can see your current stats by typing ' f'`~me`.') else: await ctx.send( f'You are too experienced to get the starter gear, {ctx.author.name}.' )
def get_clue_scroll(person, *args): try: difficulty, length = args[0] except ValueError as e: print(e) raise ValueError difficulty = int(difficulty) loot = get_loot(difficulty) users.update_inventory(person.id, loot) users.add_counter(person.id, str(difficulty), 1, key=users.CLUES_KEY) out = f'{CLUE_HEADER}' \ f'{person.mention}, you have finished your {DIFFICULTY[int(difficulty)]} clue scroll! ' \ f'You have received the following items:\n' out += print_loot(loot, difficulty) return out
async def starter_gear(self, ctx): """Gives the user a set of bronze armour.""" if ctx.channel.id == SHOP_CHANNEL or ctx.channel.id == ADVENTURES_CHANNEL or ctx.channel.id in GENERAL_CHANNELS: name = get_display_name(ctx.author) if users.read_user(ctx.author.id, key=users.COMBAT_XP_KEY) == 0: users.update_inventory(ctx.author.id, [63, 66, 69, 70, 64, 72]) await ctx.send( f'Bronze set given to {name}! You can see your items by typing `~inventory` in #bank ' f'and equip them by typing `~equip [item]`. You can see your current stats by typing ' f'`~me`. If you need help with commands, feel free to look at #welcome or ask around!' ) else: await ctx.send( f'You are too experienced to get the starter gear, {name}.' )
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 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 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.'
def get_kill_result(person, *args): """Determines the loot of a monster grind.""" try: monsterid, monster_name, num_to_kill, length = args[0] except ValueError as e: print(e) raise ValueError out = '' if mon.get_attr(monsterid, key=mon.SLAYER_KEY): factor = 0.75 else: factor = 1 loot = mon.get_loot(monsterid, int(num_to_kill), factor=factor) users.update_inventory(person.id, loot) out += print_loot(loot, person, monster_name, num_to_kill) xp_gained = mon.get_attr(monsterid, key=mon.XP_KEY) * int(num_to_kill) users.update_user(person.id, xp_gained, users.COMBAT_XP_KEY) combat_xp_formatted = '{:,}'.format(xp_gained) out += f'\nYou have also gained {combat_xp_formatted} combat xp.' return out
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
def get_result(person, *args): """Gets the result of a quest.""" try: questid, chance = args[0] except ValueError as e: print(e) raise ValueError out = f'{QUEST_HEADER}**{person.mention}, here is the result of your quest, {get_attr(questid)}**:\n' if adv.is_success(calc_chance(person.id, questid)): out += f'*{get_attr(questid, key=SUCCESS_KEY)}*\n\n' reward = get_attr(questid, key=REWARD_KEY) out += f'**Reward**:\n' loot = [] for itemid in reward: loot.extend(reward[itemid] * [itemid]) out += f'{reward[itemid]} {items.get_attr(itemid)}\n' users.update_inventory(person.id, loot) users.update_user(person.id, questid, key=users.QUESTS_KEY) else: out += f'*{get_attr(questid, key=FAILURE_KEY)}*' return out
async def jeopardy(self, ctx, textonly='f'): """Gives users GasterCash in exchange for correct answers.""" if ctx.channel.id == JEOPARDY_CHANNEL: question_args = quiz.get_new_question() category = question_args[0] value = question_args[1] question = question_args[2] answer = question_args[3] if textonly != 't': quiz.draw_jeopardy(question) await ctx.send( f"*{ctx.author.name}: I'll take {category} for {value} coins, Alex.*", file=discord.File(quiz.OUT_FILE)) else: await ctx.send( f"*{ctx.author.name}: I'll take {category} for {value} coins, Alex.*\n{question}" ) while True: message = await self.bot.wait_for('message') if message.author == ctx.author: if message.content.lower() in answer.lower() and len( message.content) > 1: amount_formatted = '{:,}'.format(value) out = f"Answer {answer} is correct! " if not users.read_user(ctx.author.id, key=users.IRONMAN_KEY): users.update_inventory(ctx.author.id, value * ['0']) out += f"{ctx.author.name}'s balance has increased by {amount_formatted} coins!" await ctx.send(out) break else: await ctx.send( f"Answer {message.content} is incorrect. Correct answer was {answer}." ) break
async def sellall(self, ctx, maxvalue=None): """Sells all items in the player's inventory (below a certain value) for GasterCoin.""" if ctx.channel.id == SHOP_CHANNEL or ctx.channel.id in GENERAL_CHANNELS: name = get_display_name(ctx.author) if maxvalue is not None: value = users.get_value_of_inventory(ctx.author.id, under=maxvalue) users.update_inventory(ctx.author.id, value * ["0"]) users.clear_inventory(ctx.author.id, under=maxvalue) value_formatted = '{:,}'.format(value) maxvalue_formatted = '{:,}'.format(int(maxvalue)) name = get_display_name(ctx.author) out = f"All items in {name}'s inventory worth under {maxvalue_formatted} coins "\ f"sold for {value_formatted} coins!" else: value = users.get_value_of_inventory(ctx.author.id) users.update_inventory(ctx.author.id, value * ["0"]) users.clear_inventory(ctx.author.id) value_formatted = '{:,}'.format(value) out = f"All items in {name}'s inventory "\ f"sold for {value_formatted} coins!" await ctx.send(out)
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
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
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
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)