Ejemplo n.º 1
0
    def test_boosts_properly_affect_damage_calculation(self):
        self.charizard.special_attack_boost = 2

        move = 'fireblast'

        dmg = calculate_damage(self.charizard, self.venusaur, move, calc_type='max')
        self.assertEqual([597], dmg)
Ejemplo n.º 2
0
    def test_burn_does_not_modify_special_move(self):
        move = 'fire Blast'

        self.venusaur.status  = constants.BURN

        dmg = calculate_damage(self.charizard, self.venusaur, move, calc_type='max')
        self.assertEqual([300], dmg)
Ejemplo n.º 3
0
    def test_burn_modifier_properly_halves_physical_damage(self):
        move = 'rock slide'

        self.venusaur.status = constants.BURN

        dmg = calculate_damage(self.venusaur, self.charizard, move, calc_type='max')
        self.assertEqual([134], dmg)
Ejemplo n.º 4
0
    def test_4x_weakness_calculates_properly(self):
        move = 'rock slide'

        dmg = calculate_damage(self.venusaur,
                               self.charizard,
                               move,
                               calc_type='max')
        self.assertEqual([268], dmg)
Ejemplo n.º 5
0
    def test_fire_blast_from_charizard_to_venusaur_without_modifiers(self):
        move = 'fire Blast'

        dmg = calculate_damage(self.charizard,
                               self.venusaur,
                               move,
                               calc_type='max')
        self.assertEqual([300], dmg)
Ejemplo n.º 6
0
    def test_stab_without_weakness_calculates_properly(self):
        move = 'sludge bomb'

        dmg = calculate_damage(self.venusaur,
                               self.charizard,
                               move,
                               calc_type='max')
        self.assertEqual([130], dmg)
Ejemplo n.º 7
0
    def test_4x_resistance_calculates_properly(self):
        move = 'gigadrain'

        dmg = calculate_damage(self.venusaur,
                               self.charizard,
                               move,
                               calc_type='max')
        self.assertEqual([27], dmg)
Ejemplo n.º 8
0
    def test_immunity_calculates_properly(self):
        move = 'earthquake'

        dmg = calculate_damage(self.venusaur,
                               self.charizard,
                               move,
                               calc_type='max')
        self.assertEqual([0], dmg)
Ejemplo n.º 9
0
    def test_flashfire_increases_fire_move_damage(self):
        move = 'fire Blast'
        self.charizard.volatile_status.add('flashfire')

        dmg = calculate_damage(self.charizard,
                               self.venusaur,
                               move,
                               calc_type='max')
        self.assertEqual([450], dmg)
Ejemplo n.º 10
0
    def test_rain_properly_amplifies_water_damage(self):

        conditions = {
            'weather': constants.RAIN
        }

        move = 'surf'

        dmg = calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max')
        self.assertEqual([261], dmg)
Ejemplo n.º 11
0
    def test_aurora_veil_properly_halves_damage(self):

        conditions = {
            'auroraveil': 1
        }

        move = 'fireblast'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')
        self.assertEqual([150], dmg)
Ejemplo n.º 12
0
    def test_light_screen_properly_halves_damage(self):

        conditions = {
            'lightscreen': 1
        }

        move = 'psychic'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')
        self.assertEqual([82], dmg)
Ejemplo n.º 13
0
    def test_reflect_properly_halves_damage(self):

        conditions = {
            'reflect': 1
        }

        move = 'rockslide'

        dmg = calculate_damage(self.venusaur, self.charizard, move, conditions, calc_type='max')
        self.assertEqual([134], dmg)
Ejemplo n.º 14
0
    def test_sun_stab_and_2x_weakness(self):

        conditions = {
            'weather': constants.SUN
        }

        move = 'fireblast'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')
        self.assertEqual([450], dmg)
Ejemplo n.º 15
0
    def test_sand_does_not_double_ground_spdef(self):

        self.venusaur.types = ['water']

        conditions = {
            'weather': constants.SAND
        }

        move = 'fireblast'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')
        self.assertEqual([75], dmg)
Ejemplo n.º 16
0
    def test_sand_increases_rock_spdef(self):

        self.venusaur.types = ['rock']

        conditions = {
            'weather': constants.SAND
        }

        move = 'fireblast'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')
        self.assertEqual([51], dmg)
Ejemplo n.º 17
0
    def test_damage_is_not_increased_if_attacker_is_not_grounded(self):
        self.charizard.types = ['fire', 'flying']

        conditions = {
            constants.TERRAIN: constants.PSYCHIC_TERRAIN
        }

        move = 'psychic'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        self.assertEqual([164], dmg)
Ejemplo n.º 18
0
    def test_psychic_terrain_makes_priority_move_do_nothing(self):
        self.charizard.types = ['fire']

        conditions = {
            constants.TERRAIN: constants.PSYCHIC_TERRAIN
        }

        move = 'machpunch'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        self.assertEqual([0], dmg)
Ejemplo n.º 19
0
    def test_grassy_terrain_increases_grass_type_move(self):
        self.charizard.types = ['fire']

        conditions = {
            constants.TERRAIN: constants.GRASSY_TERRAIN
        }

        move = 'gigadrain'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        # normally this is 17
        self.assertEqual([25], dmg)
Ejemplo n.º 20
0
    def test_misty_terrain_halves_dragon_moves(self):
        self.charizard.types = ['fire']

        conditions = {
            constants.TERRAIN: constants.MISTY_TERRAIN
        }

        move = 'outrage'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        # normally this is 103
        self.assertEqual([51], dmg)
Ejemplo n.º 21
0
    def test_electric_terrain_increases_electric_damage_for_grounded_pokemon(self):
        self.charizard.types = ['fire']

        conditions = {
            constants.TERRAIN: constants.ELECTRIC_TERRAIN
        }

        move = 'thunderbolt'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        # normally this is 41
        self.assertEqual([61], dmg)
Ejemplo n.º 22
0
    def test_psychic_terrain_increases_psychic_damage(self):
        self.charizard.types = ['fire']

        conditions = {
            constants.TERRAIN: constants.PSYCHIC_TERRAIN
        }

        move = 'psychic'

        dmg = calculate_damage(self.charizard, self.venusaur, move, conditions, calc_type='max')

        # normally this is 164
        self.assertEqual([246], dmg)
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
def get_state_instructions_from_move(mutator, attacking_move, defending_move,
                                     attacker, defender, first_move,
                                     instructions):
    instructions.frozen = False

    if constants.SWITCH_STRING in attacking_move:
        return instruction_generator.get_instructions_from_switch(
            mutator, attacker, attacking_move[constants.SWITCH_STRING],
            instructions)

    mutator.apply(instructions.instructions)
    attacking_side = instruction_generator.get_side_from_state(
        mutator.state, attacker)
    defending_side = instruction_generator.get_side_from_state(
        mutator.state, defender)
    attacking_pokemon = attacking_side.active
    defending_pokemon = defending_side.active
    active_weather = mutator.state.weather

    if cannot_use_move(attacking_pokemon, attacking_move):
        attacking_move = lookup_move(constants.DO_NOTHING_MOVE)

    conditions = {
        constants.REFLECT:
        defending_side.side_conditions[constants.REFLECT],
        constants.LIGHT_SCREEN:
        defending_side.side_conditions[constants.LIGHT_SCREEN],
        constants.AURORA_VEIL:
        defending_side.side_conditions[constants.AURORA_VEIL],
        constants.WEATHER:
        active_weather,
        constants.TERRAIN:
        mutator.state.field
    }

    if attacking_pokemon.hp == 0:
        # if the attacker is dead, remove the 'flinched' volatile-status if it has it and exit early
        # this triggers if the pokemon moves second but the first attack knocked it out
        mutator.reverse(instructions.instructions)
        all_instructions = instruction_generator.get_instructions_from_flinched(
            mutator, attacker, instructions)
        return all_instructions

    attacking_move = update_damage_calc_from_abilities_and_items(
        attacking_pokemon, defending_pokemon, attacking_move, defending_move,
        first_move, mutator.state.weather)

    damage_amounts = None
    move_status_effect = None
    flinch_accuracy = None
    boosts = None
    boosts_target = None
    boosts_chance = None
    side_condition = None
    hazard_clearing_move = None
    volatile_status = attacking_move.get(constants.VOLATILE_STATUS)

    move_accuracy = min(100, attacking_move[constants.ACCURACY])
    move_status_accuracy = move_accuracy

    move_target = attacking_move[constants.TARGET]
    if move_target == constants.SELF:
        move_status_target = attacker
    else:
        move_status_target = defender

    if attacking_move[constants.ID] in constants.HAZARD_CLEARING_MOVES:
        hazard_clearing_move = attacking_move

    # move is a damaging move
    if attacking_move[constants.CATEGORY] in constants.DAMAGING_CATEGORIES:
        damage_amounts = calculate_damage(attacking_pokemon,
                                          defending_pokemon,
                                          attacking_move,
                                          conditions=conditions,
                                          calc_type=config.damage_calc_type)

        attacking_move_secondary = attacking_move[constants.SECONDARY]
        attacking_move_self = attacking_move.get(constants.SELF)
        if attacking_move_secondary:
            # flinching (iron head)
            if attacking_move_secondary.get(
                    constants.VOLATILE_STATUS
            ) == constants.FLINCH and first_move:
                flinch_accuracy = attacking_move_secondary.get(
                    constants.CHANCE)

            # secondary status effects (thunderbolt paralyzing)
            elif attacking_move_secondary.get(constants.STATUS) is not None:
                move_status_effect = attacking_move_secondary[constants.STATUS]
                move_status_accuracy = attacking_move_secondary[
                    constants.CHANCE]

            # boosts from moves that boost in secondary (charge beam)
            elif attacking_move_secondary.get(constants.SELF) is not None:
                if constants.BOOSTS in attacking_move_secondary[
                        constants.SELF]:
                    boosts = attacking_move_secondary[constants.SELF][
                        constants.BOOSTS]
                    boosts_target = attacker
                    boosts_chance = attacking_move_secondary[constants.CHANCE]

            # boosts from secondary, but to the defender (crunch)
            elif attacking_move_secondary and attacking_move_secondary.get(
                    constants.BOOSTS) is not None:
                boosts = attacking_move_secondary[constants.BOOSTS]
                boosts_target = defender
                boosts_chance = attacking_move_secondary[constants.CHANCE]

        # boosts from secondary, but it is a guaranteed boost (dracometeor)
        elif attacking_move_self:
            if constants.BOOSTS in attacking_move_self:
                boosts = attacking_move_self[constants.BOOSTS]
                boosts_target = attacker
                boosts_chance = 100

        # guaranteed boosts from a damaging move (none in the moves JSON but items/abilities can cause this)
        elif constants.BOOSTS in attacking_move:
            boosts = attacking_move[constants.BOOSTS]
            boosts_target = attacker if attacking_move[
                constants.TARGET] in constants.MOVE_TARGET_SELF else defender
            boosts_chance = 100

    # move is a status move
    else:
        move_status_effect = attacking_move.get(constants.STATUS)
        side_condition = attacking_move.get(constants.SIDE_CONDITIONS)

        # boosts from moves that only boost (dragon dance)
        if attacking_move.get(constants.BOOSTS) is not None:
            boosts = attacking_move[constants.BOOSTS]
            boosts_target = attacker if attacking_move[
                constants.TARGET] == constants.SELF else defender
            boosts_chance = attacking_move[constants.ACCURACY]

    mutator.reverse(instructions.instructions)

    all_instructions = instruction_generator.get_instructions_from_flinched(
        mutator, attacker, instructions)

    temp_instructions = []
    for instruction_set in all_instructions:
        temp_instructions += instruction_generator.get_instructions_from_statuses_that_freeze_the_state(
            mutator, attacker, defender, attacking_move, defending_move,
            instruction_set)
    all_instructions = temp_instructions

    if attacking_move[
            constants.ID] in instruction_generator.SPECIAL_LOGIC_MOVES:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_instructions_from_special_logic_move(
                mutator, attacking_move[constants.ID], instruction_set)
        return temp_instructions

    if damage_amounts is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            amount_of_damage_rolls = len(damage_amounts)
            for dmg in damage_amounts:
                these_instructions = copy(instruction_set)
                these_instructions.update_percentage(1 /
                                                     amount_of_damage_rolls)
                temp_instructions += instruction_generator.get_states_from_damage(
                    mutator, defender, dmg, move_accuracy, attacking_move,
                    these_instructions)
        all_instructions = temp_instructions

    if side_condition is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_instructions_from_side_conditions(
                mutator, attacker, move_target, side_condition,
                instruction_set)
        all_instructions = temp_instructions

    if hazard_clearing_move is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_instructions_from_hazard_clearing_moves(
                mutator, attacker, attacking_move, instruction_set)
        all_instructions = temp_instructions

    if volatile_status is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_state_from_volatile_status(
                mutator, volatile_status, attacker, move_target, first_move,
                instruction_set)
        all_instructions = temp_instructions

    if move_status_effect is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_states_from_status_effects(
                mutator, move_status_target, move_status_effect,
                move_status_accuracy, instruction_set)
        all_instructions = temp_instructions

    if boosts is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_states_from_boosts(
                mutator, boosts_target, boosts, boosts_chance, instruction_set)
        all_instructions = temp_instructions

    if attacking_move.get(constants.HEAL) is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_state_from_attacker_recovery(
                mutator, attacker, attacking_move, instruction_set)
        all_instructions = temp_instructions

    if flinch_accuracy is not None:
        temp_instructions = []
        for instruction_set in all_instructions:
            temp_instructions += instruction_generator.get_states_from_flinching_moves(
                defender, flinch_accuracy, first_move, instruction_set)
        all_instructions = temp_instructions

    temp_instructions = []
    for instruction_set in all_instructions:
        temp_instructions += instruction_generator.get_state_from_drag(
            mutator, attacking_move, attacker, move_target, instruction_set)
    all_instructions = temp_instructions

    if switch_out_move_triggered(attacking_move, damage_amounts):
        temp_instructions = []
        for i in all_instructions:
            best_switch = get_best_switch_pokemon(mutator, i, attacker,
                                                  attacking_side,
                                                  defending_move, first_move)
            if best_switch is not None:
                temp_instructions += instruction_generator.get_instructions_from_switch(
                    mutator, attacker, best_switch, i)
            else:
                temp_instructions.append(i)

        all_instructions = temp_instructions

    return all_instructions