def calculate_damage(state, attacking_side_string, attacking_move, defending_move, calc_type='average'): # a wrapper for `_calculate_damage` that takes into account move/item/ability special-effects from showdown.engine.find_state_instructions import update_attacking_move from showdown.engine.find_state_instructions import user_moves_first attacking_move_dict = get_move(attacking_move) if defending_move.startswith(constants.SWITCH_STRING + " "): defending_move_dict = { constants.SWITCH_STRING: defending_move.split(constants.SWITCH_STRING)[-1] } else: defending_move_dict = get_move(defending_move) if attacking_side_string == constants.SELF: attacking_side = state.self defending_side = state.opponent elif attacking_side_string == constants.OPPONENT: attacking_side = state.opponent defending_side = state.self else: raise ValueError( "attacking_side_string must be one of: ['self', 'opponent']") conditions = { constants.REFLECT: state.opponent.side_conditions[constants.REFLECT], constants.LIGHT_SCREEN: state.opponent.side_conditions[constants.LIGHT_SCREEN], constants.AURORA_VEIL: state.opponent.side_conditions[constants.AURORA_VEIL], constants.WEATHER: state.weather, constants.TERRAIN: state.field } attacker_moves_first = user_moves_first(state, attacking_move_dict, defending_move_dict) # a charge move doesn't need to charge when only calculating damage attacking_move_dict[constants.FLAGS].pop(constants.CHARGE, None) attacking_move_dict = update_attacking_move( attacking_side.active, defending_side.active, attacking_move_dict, defending_move_dict, attacker_moves_first, state.weather) return _calculate_damage(attacking_side.active, defending_side.active, attacking_move_dict, conditions=conditions, calc_type=calc_type)
def find_best_move(self): state = self.create_state() my_options = self.get_all_options()[0] moves = [] switches = [] for option in my_options: if option.startswith(constants.SWITCH_STRING + " "): switches.append(option) else: moves.append(option) if self.force_switch or not moves: return format_decision(self, switches[0]) conditions = { constants.REFLECT: state.opponent.side_conditions[constants.REFLECT], constants.LIGHT_SCREEN: state.opponent.side_conditions[constants.LIGHT_SCREEN], constants.AURORA_VEIL: state.opponent.side_conditions[constants.AURORA_VEIL], constants.WEATHER: state.weather, constants.TERRAIN: state.field } most_damage = -1 choice = None for move in moves: move_dict = all_move_json[move] attacking_move = update_attacking_move(state.self.active, state.opponent.active, move_dict, {}, False, state.weather) damage_amounts = calculate_damage(state.self.active, state.opponent.active, attacking_move, conditions=conditions) damage = damage_amounts[0] if damage_amounts else 0 if damage > most_damage: choice = move most_damage = damage return format_decision(self, choice)