def set_aside_dead_minions(self, own_board: PlayerBoard, enemy_board: PlayerBoard): """Remove any dead minions. Return the List of minions to process any deathrattles and reborn triggers. Arguments: board {PlayerBoard} -- Player board to check for dead minions """ dead_minions = own_board.select_dead() left_neighors = [] for minion in dead_minions: left_neighors.append(minion.left_neighbor) # Dead minions care about their left neighbor for deathrattle/reborn positioning for index, minion in enumerate(dead_minions): own_board.remove_minion(minion, enemy_board) minion.left_neighbor = left_neighors[index] return dead_minions
def check_deaths(self, attacking_player_board: PlayerBoard, defending_player_board: PlayerBoard): """Check deaths on both sides, collect death rattles, process them and resolve consequences (immediate attacks / reborn triggers) Arguments: attacking_player_board {PlayerBoard} -- Player board of attacking player defending_player_board {PlayerBoard} -- Player board of defending player """ # General flow of resolving death states: # Resolve attacker deathrattles from left to right, multiplied by baron # Resolve extra attacks after each deathrattle resolves (then recursively check deaths) # Resolve defender deathrattles from left to right, multiplied by baron # Resolve extra attacks after each deathrattle resolves (then recursively check deaths) # There are some DRY vibes here but for now this is fine attacker_dead_minions = self.set_aside_dead_minions( attacking_player_board, defending_player_board) defender_dead_minions = self.set_aside_dead_minions( defending_player_board, attacking_player_board) if len(attacker_dead_minions) == 0 and len(defender_dead_minions) == 0 \ and len(attacking_player_board.get_immediate_attack_minions()) == 0 \ and len(defending_player_board.get_immediate_attack_minions()) == 0: return # Resolve death rattles and 'attacks immediately' triggers. Attacker first, then defender # TODO: immediate attacks on defender side resolve before attacks deathrattles? # TODO: Is there a consistent order to deathrattles?? for minion in attacker_dead_minions: for deathrattle in minion.deathrattles: for _ in range(attacking_player_board.deathrattle_multiplier): deathrattle.trigger(minion, attacking_player_board, defending_player_board) # Resolve "after a friendly minion dies" triggers. ie soul juggles after deathrattles # TODO: Refactor for performance for minion in attacking_player_board.get_living_minions(): for dead_minion in attacker_dead_minions: minion.on_friendly_removal_after(dead_minion, attacking_player_board, defending_player_board) for minion in defender_dead_minions: for deathrattle in minion.deathrattles: for _ in range(defending_player_board.deathrattle_multiplier): deathrattle.trigger(minion, defending_player_board, attacking_player_board) for minion in defending_player_board.get_living_minions(): for dead_minion in defender_dead_minions: minion.on_friendly_removal_after(dead_minion, defending_player_board, attacking_player_board) # Process deaths here again to see if death rattles resulted in more deaths if len(attacking_player_board.select_dead()) > 0 or len( defending_player_board.select_dead()): self.check_deaths(attacking_player_board, defending_player_board) # Resolve reborns after deathrattles for minion in attacker_dead_minions: if minion.reborn and not minion.reborn_triggered: minion.trigger_reborn(attacking_player_board) for minion in defender_dead_minions: if minion.reborn and not minion.reborn_triggered: minion.trigger_reborn(defending_player_board) # Continue to resolve extra attacks until all are done while attacking_player_board.get_immediate_attack_minions( ) or defending_player_board.get_immediate_attack_minions(): # TODO: Is there a priority for resolving pirate attacks on each other? Are they queued up? self.resolve_extra_attacks(attacking_player_board, defending_player_board) self.resolve_extra_attacks(defending_player_board, attacking_player_board)