async def begin(self, ctx, *args): """Begins combat in the channel. Users must add tokens then start rounds""" self.init_tracker = InitiativeTracker() if len(args) == 0: await ctx.send("Battle started. Now add tokens with !init add...") else: await ctx.send("Battle started.") await ctx.invoke(self.bot.get_command("init add"), arg=' '.join(args))
def test_remove_spaces_in_name_init_tracker(): t = InitiativeTracker() assert t.count_tokens() == 0 t.add_token("Goblin", 4) t.add_token("Vince McFighty", 2) assert t.count_tokens() == 6 removed = t.remove_token("Vince McFighty", 2) assert removed == 2 assert t.count_tokens() == 4
def test_add_token_init_tracker(): t = InitiativeTracker() assert t.count_tokens() == 0 t.add_token("Goblin", 4) assert t.count_tokens() == 4 assert t.count_token("Goblin") == 4 assert t.count_token("Goldfish") == 0
def test_remove_all_tokens_init_tracker(): t = InitiativeTracker() assert t.count_tokens() == 0 t.add_token("Goblin", 4) assert t.count_token("Goblin") == 4 removed = t.remove_token("Goblin", 6) assert removed == 4 assert t.count_token("Goblin") == 0
def test_remove_missing_tokens_init_tracker(): t = InitiativeTracker() assert t.count_tokens() == 0 t.add_token("Goblin", 4) removed = t.remove_token("Ogre", 2) assert removed == 0 assert t.count_token("Goblin") == 4
def test_start_round_init_tracker(): t = InitiativeTracker() t.add_token("Goblin", 4) t.add_token("Vince McFighty", 2) t.start_round() assert t.in_round assert t.count_round_tokens() == 7 assert t.round_num == 1 assert t.drawn_log == [[]] drawn_tokens = [] while (True): popped = t.draw_token() print(popped, t.round_last_drawn) drawn_tokens.append(popped) if popped == END_OF_ROUND_TOKEN: break assert drawn_tokens.count("Goblin") + t.round_bag.count("Goblin") == 4 assert drawn_tokens.count("Vince McFighty") + t.round_bag.count( "Vince McFighty") == 2 assert drawn_tokens[-1] == END_OF_ROUND_TOKEN assert t.round_bag.count(END_OF_ROUND_TOKEN) == 0
class InitiativeCog(commands.Cog): """ Initiative tracking commands. Use !help init for more info. """ def __init__(self, bot): self.bot = bot self.init_tracker = None @commands.group(aliases=['i'], invoke_without_command=True) async def init(self, ctx): """Commands to help track initiative.""" await ctx.send(f"Incorrect usage. Use {ctx.prefix}help init for help.") # Borrowed this from avrae async def cog_check(self, ctx): if ctx.guild is None: raise NoPrivateMessage() return True @init.command(aliases=["start"]) async def begin(self, ctx, *args): """Begins combat in the channel. Users must add tokens then start rounds""" self.init_tracker = InitiativeTracker() if len(args) == 0: await ctx.send("Battle started. Now add tokens with !init add...") else: await ctx.send("Battle started.") await ctx.invoke(self.bot.get_command("init add"), arg=' '.join(args)) @init.command() async def end(self, ctx): if self.init_tracker is None: await ctx.send( "It looks like there is no current initiative tracker") else: await ctx.send("Battle is now ended") self.init_tracker = None @init.command( name="add", help="Adds [number] [tokens] to the bag. May list more than one player" ) async def add(self, ctx, *, arg): if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) return tokens = re.findall(r'([0-9]+) ([^0-9]+)', arg) if tokens == []: raise ArgumentParsingError( 'Argument should be of the form "NUM Token NUM Token"') output_string = "" for (count, token) in tokens: try: count = int(count) token = token.rstrip() self.init_tracker.add_token(token, count) output_string += f"Added {count} {token} tokens.\n" except Exception as e: print(e) output_string = f"Unable to parse: {arg}" await ctx.send(output_string) @init.command(name="remove", aliases=["delete", "del"], help="Removes [number] [tokens] from the bag") async def remove(self, ctx, *, arg): '''Removes N tokens from the bag''' r = re.match(r'([0-9]+) (.+)$', arg) if not r: raise ArgumentParsingError( "Must be of the format `number token_name`") token = r.group(2) count = int(r.group(1)) if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) return in_bag = self.init_tracker.count_token(token) removed = self.init_tracker.remove_token(token, count) if removed < count: await ctx.send( f"You asked to remove {count} {token} tokens, but only {removed} were in the bag (0 left)" ) elif removed < in_bag: await ctx.send( f"Removed {removed} {token} tokens from the bag ({in_bag - removed} left)" ) else: await ctx.send( f"Removed all {removed} {token} tokens from the bag (0 left)") @init.command(name="show", aliases=["bag"]) async def show(self, ctx): """Prints out a representation of the tokens in the bag""" if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) return bag = self.init_tracker.current_tokens() output_string = "Initiative Bag:\n" for key in sorted(bag): output_string += f"- **{key}** ({bag[key]})\n" await ctx.send(output_string) @init.command(name="round", help="Begin a round of combat") async def round(self, ctx): """Starts a new round and returns the first token""" if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) return self.init_tracker.start_round() await ctx.send( f"Starting round {self.init_tracker.round_num} of combat! Shuffling the bag..." ) await ctx.invoke(self.bot.get_command("init draw")) @commands.command(name="round", hidden=True) async def roundAlias(self, ctx): await ctx.invoke(self.bot.get_command("init round")) @init.command() async def draw(self, ctx): """Returns a token drawn in the current round""" if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) elif not self.init_tracker.in_round: await ctx.send(NOT_IN_ROUND_MESSAGE) else: token = self.init_tracker.draw_token() if token == END_OF_ROUND_TOKEN: await ctx.send(f"END OF ROUND {self.init_tracker.round_num}") else: await ctx.send(f"Current Turn: **{token}**") @commands.command(name="draw", hidden=True) async def drawAlias(self, ctx): await ctx.invoke(self.bot.get_command("init draw")) @init.command(name="current") async def current_turn(self, ctx): if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) elif not self.init_tracker.in_round: await ctx.send(NOT_IN_ROUND_MESSAGE) else: token = self.init_tracker.current_token() history = self.init_tracker.current_round_history()[:-1] history.reverse() await ctx.send( f"ROUND {self.init_tracker.round_num} current: **{token}** recent: {', '.join(history)}" ) @commands.command(name="current", aliases=["turn", "now"], hidden=True) async def current_turn_alias(self, ctx): await ctx.invoke(self.bot.get_command("init current")) @init.command(name="delay", help="Puts a token back in the bag and reshuffles it") async def delay(self, ctx, token: str): if self.init_tracker is None: await ctx.send(NO_INIT_TRACKER_MESSAGE) elif not self.init_tracker.in_round: await ctx.send(NOT_IN_ROUND_MESSAGE) else: self.init_tracker.delay_token(token) await ctx.send(f"Pushing {token} back into the initiative tracker")
def test_empty_init_tracker(): t = InitiativeTracker() t.add_token("Henchman") assert t.count_tokens() == 1 t.empty() assert t.count_tokens() == 0
def test_draw_token(): t = InitiativeTracker() t.in_round = True t.drawn_log = [[]] t.round_bag = ["Goblin", "Ogre", END_OF_ROUND_TOKEN, "Goblin"] assert t.count_round_tokens() == 4 tok = t.draw_token() assert tok == "Goblin" assert t.in_round assert t.count_round_tokens() == 3 assert t.round_bag == ["Ogre", END_OF_ROUND_TOKEN, "Goblin"] assert t.drawn_log == [["Goblin"]] tok = t.draw_token() assert tok == "Ogre" assert t.in_round assert t.count_round_tokens() == 2 assert t.round_bag == [END_OF_ROUND_TOKEN, "Goblin"] assert t.drawn_log == [["Goblin", "Ogre"]] tok = t.draw_token() assert tok == END_OF_ROUND_TOKEN assert not t.in_round assert t.round_bag == ["Goblin"] assert t.drawn_log == [["Goblin", "Ogre", END_OF_ROUND_TOKEN]] tok = t.draw_token() assert tok == END_OF_ROUND_TOKEN assert t.round_bag == ["Goblin"] assert t.drawn_log == [["Goblin", "Ogre", END_OF_ROUND_TOKEN]]
def test_display_initiative(): t = InitiativeTracker() t.add_token("Goblin", 2) t.add_token("Ogre", 1) t.add_token("Henchman", 2) t.add_token("Goblin", 2) t.add_token("Hero Person", 2) assert t.display_tokens() == "Goblin(4) Henchman(2) Hero Person(2) Ogre(1)"
def test_init_initiative_tracker(): t = InitiativeTracker() assert t.bag == []
def test_delay_init_tracker(): t = InitiativeTracker() t.add_token("Goblin", 4) t.add_token("Vince McFighty", 2) t.add_token("Dragon", 20) t.start_round() assert t.count_round_tokens() == 27 turn1 = t.round_bag.copy() drawn = t.draw_token() if drawn != END_OF_ROUND_TOKEN: assert t.count_round_tokens() == 26 t.delay_token(drawn) assert t.count_round_tokens() == 27 turn1a = t.round_bag.copy() assert turn1a != turn1
def test_remove_shuffle(): t = InitiativeTracker() t.add_token("Goblin", 8) t.add_token("Vince McFighty", 2) t.add_token("Ogre", 2) t.start_round() turn1 = t.round_bag.copy() removed = t.remove_token("Ogre", 2) assert removed == 2 turn2 = t.round_bag.copy() assert len(turn1) == 2 + len(turn2) turn1.remove("Ogre") turn1.remove("Ogre") assert len(turn1) == len(turn2) assert turn1 != turn2
def test_initiative_shuffles(): t = InitiativeTracker() t.add_token("Goblin", 4) t.add_token("Vince McFighty", 2) t.add_token("Dragon", 20) t.start_round() turn1 = t.round_bag.copy() t.start_round() turn2 = t.round_bag.copy() assert turn1 != turn2