Exemple #1
0
    def test_opponent_has_no_moves_when_uturn_happens_after_switch(self):
        self.battle.user.active.moves = [
            Move('tackle'),
            Move('charm'),
            Move('uturn'),
        ]
        self.battle.opponent.active.moves = [
            Move('tackle'),
            Move('charm'),
        ]

        self.battle.user.reserve = [
            Pokemon('caterpie', 100),
            Pokemon('spinarak', 100)
        ]
        self.battle.opponent.reserve = [Pokemon('caterpie', 100)]

        # using uturn on the previous turn would cause force_switch to be True
        self.battle.force_switch = True

        self.battle.turn = 5

        self.battle.user.last_used_move = LastUsedMove(
            move='uturn',
            pokemon_name='pikachu',
            turn=5,
        )

        self.battle.opponent.last_used_move = LastUsedMove(
            move='switch pikachu', pokemon_name=None, turn=5)

        expected_options = (['switch caterpie', 'switch spinarak'], ['splash'])

        self.assertEqual(expected_options, self.battle.get_all_options())
Exemple #2
0
def move(battle, split_msg):
    move_name = normalize_name(split_msg[3].strip().lower())

    if is_opponent(battle, split_msg):
        side = battle.opponent
        pkmn = battle.opponent.active
    else:
        side = battle.user
        pkmn = battle.user.active

    # add the move to it's moves if it hasn't been seen
    # decrement the PP by one
    # if the move is unknown, do nothing
    move_object = pkmn.get_move(move_name)
    if move_object is None:
        new_move = pkmn.add_move(move_name)
        if new_move is not None:
            new_move.current_pp -= 1
    else:
        move_object.current_pp -= 1
        logger.debug("{} already has the move {}. Decrementing the PP by 1".format(pkmn.name, move_name))

    # if this pokemon used two different moves without switching,
    # set a flag to signify that it cannot have a choice item
    if (
            is_opponent(battle, split_msg) and
            side.last_used_move.pokemon_name == side.active.name and
            side.last_used_move.move != move_name
    ):
        logger.debug("{} used two different moves - it cannot have a choice item".format(pkmn.name))
        pkmn.can_have_choice_item = False
        if pkmn.item in constants.CHOICE_ITEMS:
            logger.warning("{} has a choice item, but used two different moves - setting it's item to UNKNOWN".format(pkmn.name))
            pkmn.item = constants.UNKNOWN_ITEM

    try:
        category = all_move_json[move_name][constants.CATEGORY]
        logger.debug("Setting {}'s last used move: {}".format(pkmn.name, move_name))
        side.last_used_move = LastUsedMove(
            pokemon_name=pkmn.name,
            move=move_name
        )
    except KeyError:
        category = None
        side.last_used_move = LastUsedMove(
            pokemon_name=pkmn.name,
            move=constants.DO_NOTHING_MOVE
        )

    # if this pokemon used a damaging move, eliminate the possibility of it having a lifeorb
    # the lifeorb will reveal itself if it has it
    if category in constants.DAMAGING_CATEGORIES and not any([normalize_name(a) in ['sheerforce', 'magicguard'] for a in pokedex[pkmn.name][constants.ABILITIES].values()]):
        logger.debug("{} used a damaging move - not guessing lifeorb anymore".format(pkmn.name))
        pkmn.can_have_life_orb = False

    # there is nothing special in the protocol for "wish" - it must be extracted here
    if move_name == constants.WISH and 'still' not in split_msg[4]:
        logger.debug("{} used wish - expecting {} health of recovery next turn".format(side.active.name, side.active.max_hp/2))
        side.wish = (2, side.active.max_hp/2)
def move(battle, split_msg):
    """The opponent's pokemon has made a move - add it to that pokemon's move list if necessary"""
    move_name = normalize_name(split_msg[3].strip().lower())
    if is_opponent(battle, split_msg):
        pkmn = battle.opponent.active
        move = pkmn.get_move(move_name)
        if move is None:
            new_move = pkmn.add_move(move_name)
            if new_move is not None:
                new_move.current_pp -= 1
        else:
            move.current_pp -= 1
            logger.debug(
                "{} already has the move {}. Decrementing the PP by 1".format(
                    pkmn.name, move_name))

        logger.debug("Setting opponent's last used move: {} - {}".format(
            battle.opponent.active.name, move_name))

        # if this pokemon used two different moves without switching,
        # set a flag to signify that it cannot have a choice item
        if (battle.opponent.last_used_move.pokemon_name
                == battle.opponent.active.name
                and battle.opponent.last_used_move.move != move_name):
            logger.debug(
                "Opponent's {} used two different moves - it cannot have a choice item"
                .format(battle.opponent.active.name))
            battle.opponent.active.can_have_choice_item = False

        battle.opponent.last_used_move = LastUsedMove(
            pokemon_name=battle.opponent.active.name, move=move_name)
Exemple #4
0
async def async_pick_move(battle):
    battle_copy = deepcopy(battle)
    if battle_copy.request_json:
        battle_copy.user.from_json(battle_copy.request_json)

    loop = asyncio.get_event_loop()
    with concurrent.futures.ThreadPoolExecutor() as pool:
        best_move = await loop.run_in_executor(
            pool, battle_copy.find_best_move
        )
    choice = best_move[0]
    if constants.SWITCH_STRING in choice:
        battle.user.last_used_move = LastUsedMove(battle.user.active.name, "switch {}".format(choice.split()[-1]), battle.turn)
    else:
        battle.user.last_used_move = LastUsedMove(battle.user.active.name, choice.split()[2], battle.turn)
    return best_move
def switch_or_drag(battle, split_msg):
    if is_opponent(battle, split_msg):
        side = battle.opponent
        logger.debug("Opponent has switched - clearing the last used move")
    else:
        side = battle.user
        side.side_conditions[constants.TOXIC_COUNT] = 0

    if side.active is not None:
        # set the pkmn's types back to their original value if the types were changed
        if constants.TYPECHANGE in side.active.volatile_statuses:
            original_types = pokedex[side.active.name][constants.TYPES]
            logger.debug(
                "{} had it's type changed - changing its types back to {}".
                format(side.active.name, original_types))
            side.active.types = original_types

        # if the target was transformed, reset its transformed attributes
        if constants.TRANSFORM in side.active.volatile_statuses:
            logger.debug(
                "{} was transformed. Resetting its transformed attributes".
                format(side.active.name))
            side.active.stats = calculate_stats(side.active.base_stats,
                                                side.active.level)
            side.active.ability = None
            side.active.moves = []
            side.active.types = pokedex[side.active.name][constants.TYPES]

        # reset the boost of the pokemon being replaced
        side.active.boosts.clear()

        # reset the volatile statuses of the pokemon being replaced
        side.active.volatile_statuses.clear()

        # reset toxic count for this side
        side.side_conditions[constants.TOXIC_COUNT] = 0

    # check if the pokemon exists in the reserves
    # if it does not, then the newly-created pokemon is used (for formats without team preview)
    pkmn = Pokemon.from_switch_string(split_msg[3])
    pkmn = find_pokemon_in_reserves(pkmn.name, side.reserve)

    if pkmn is None:
        pkmn = Pokemon.from_switch_string(split_msg[3])
    else:
        side.reserve.remove(pkmn)

    side.last_used_move = LastUsedMove(pokemon_name=None,
                                       move='switch {}'.format(pkmn.name),
                                       turn=battle.turn)

    # pkmn != active is a special edge-case for Zoroark
    if side.active is not None and pkmn != side.active:
        side.reserve.append(side.active)

    side.active = pkmn
    if side.active.name in constants.UNKOWN_POKEMON_FORMES:
        side.active = Pokemon.from_switch_string(split_msg[3])
Exemple #6
0
    def test_non_choice_item_possession_returns_false(self):
        self.battler.active.item = ''
        self.battler.last_used_move = LastUsedMove(pokemon_name='pikachu',
                                                   move='tackle')
        self.battler.lock_moves()

        self.assertFalse(self.battler.active.get_move('volttackle').disabled)
        self.assertFalse(self.battler.active.get_move('thunderbolt').disabled)
        self.assertFalse(self.battler.active.get_move('agility').disabled)
        self.assertFalse(self.battler.active.get_move('doubleteam').disabled)
Exemple #7
0
    def test_choice_item_with_previous_move_being_a_switch_returns_false(self):
        self.battler.active.item = 'choicescarf'
        self.battler.last_used_move = LastUsedMove(pokemon_name='caterpie',
                                                   move='switch')
        self.battler.lock_moves()

        self.assertFalse(self.battler.active.get_move('volttackle').disabled)
        self.assertFalse(self.battler.active.get_move('thunderbolt').disabled)
        self.assertFalse(self.battler.active.get_move('agility').disabled)
        self.assertFalse(self.battler.active.get_move('doubleteam').disabled)
Exemple #8
0
    def test_fakeout_is_not_disabled_when_the_last_used_move_was_a_switch(
            self):
        self.battler.active.moves.append(Move('fakeout'))
        self.battler.last_used_move = LastUsedMove(pokemon_name='caterpie',
                                                   move='switch',
                                                   turn=0)

        self.battler.lock_moves()

        self.assertFalse(self.battler.active.get_move('fakeout').disabled)
Exemple #9
0
    def test_fakeout_gets_locked_when_last_used_move_was_by_the_active_pokemon(
            self):
        self.battler.active.moves.append(Move('fakeout'))
        self.battler.last_used_move = LastUsedMove(
            pokemon_name='pikachu',  # the current active pokemon
            move='volttackle',
            turn=0)

        self.battler.lock_moves()

        self.assertTrue(self.battler.active.get_move('fakeout').disabled)
Exemple #10
0
    def test_choice_item_with_previous_move_used_by_this_pokemon_returns_true(
            self):
        self.battler.active.item = 'choicescarf'
        self.battler.last_used_move = LastUsedMove(pokemon_name='pikachu',
                                                   move='volttackle')

        self.battler.lock_moves()

        self.assertFalse(self.battler.active.get_move('volttackle').disabled)

        self.assertTrue(self.battler.active.get_move('thunderbolt').disabled)
        self.assertTrue(self.battler.active.get_move('agility').disabled)
        self.assertTrue(self.battler.active.get_move('doubleteam').disabled)
Exemple #11
0
    def test_opponent_has_no_moves_when_uturn_kills_and_opponent_has_not_moved_yet(
            self):
        self.battle.user.active.moves = [
            Move('tackle'),
            Move('charm'),
            Move('uturn'),
        ]
        self.battle.opponent.active.moves = [
            Move('tackle'),
            Move('charm'),
        ]

        self.battle.user.reserve = [
            Pokemon('caterpie', 100),
            Pokemon('spinarak', 100)
        ]
        self.battle.opponent.reserve = [Pokemon('caterpie', 100)]

        # using uturn on the previous turn would cause force_switch to be True
        self.battle.force_switch = True

        # opponent has died from uturn
        self.battle.opponent.active.hp = 0

        self.battle.turn = 5

        self.battle.user.last_used_move = LastUsedMove(
            move='uturn',
            pokemon_name='pikachu',
            turn=5,
        )

        # the opponent's last move would have been from the turn before (turn 4), meaning it hasn't moved yet
        self.battle.opponent.last_used_move = LastUsedMove(
            move='tackle', pokemon_name='pikachu', turn=4)

        expected_options = (['switch caterpie', 'switch spinarak'], ['splash'])

        self.assertEqual(expected_options, self.battle.get_all_options())
Exemple #12
0
async def async_pick_move(battle, agent=None):
    battle_copy = deepcopy(battle)
    if battle_copy.request_json:
        battle_copy.user.from_json(battle_copy.request_json)

    loop = asyncio.get_event_loop()
    if agent == None:  # so we are dealing with a non neural network bot
        with concurrent.futures.ThreadPoolExecutor() as pool:
            best_move = await loop.run_in_executor(
                pool, battle_copy.find_best_move
            )
    else:  # modify this?
        #with concurrent.futures.ThreadPoolExecutor() as pool:
            #best_move = await loop.run_in_executor(
            #    pool, battle_copy.find_best_move, agent
            #)
        best_move = await battle_copy.find_best_move(agent)
    choice = best_move[0]
    if constants.SWITCH_STRING in choice:
        battle.user.last_used_move = LastUsedMove(battle.user.active.name, "switch {}".format(choice.split()[-1]), battle.turn)
    else:
        battle.user.last_used_move = LastUsedMove(battle.user.active.name, choice.split()[2], battle.turn)
    return best_move
Exemple #13
0
def switch_or_drag(battle, split_msg):
    """The opponent's pokemon has changed
       If the new one hasn't been seen, create it"""
    if is_opponent(battle, split_msg):
        logger.debug("Opponent has switched - clearing the last used move")
        battle.opponent.last_used_move = LastUsedMove(pokemon_name=None,
                                                      move='switch')

        battle.opponent.side_conditions[constants.TOXIC_COUNT] = 0

        if battle.opponent.active is not None:
            # reset the boost of the pokemon being replaced
            battle.opponent.active.boosts.clear()

            if constants.DYNAMAX in battle.opponent.active.volatile_statuses:
                battle.opponent.active.hp /= 2
                battle.opponent.active.max_hp /= 2
                logger.debug(
                    "Opponent ended dynamax - halving their HP to {}/{}".
                    format(battle.opponent.active.hp,
                           battle.opponent.active.max_hp))

            # reset the volatile statuses of the pokemon being replaced
            battle.opponent.active.volatile_statuses.clear()

        # check if the pokemon exists in the reserves
        # if it does not, then the newly-created pokemon is used (for formats without team preview)
        pkmn = Pokemon.from_switch_string(split_msg[3])
        pkmn = find_pokemon_in_reserves(pkmn.name, battle.opponent.reserve)

        if pkmn is None:
            pkmn = Pokemon.from_switch_string(split_msg[3])
        else:
            battle.opponent.reserve.remove(pkmn)

        # pkmn != active is a special edge-case for Zoroark
        if battle.opponent.active is not None and pkmn != battle.opponent.active:
            battle.opponent.reserve.append(battle.opponent.active)

        battle.opponent.active = pkmn
        if battle.opponent.active.name in constants.UNKOWN_POKEMON_FORMES:
            battle.opponent.active = Pokemon.from_switch_string(split_msg[3])

    else:
        battle.user.side_conditions[constants.TOXIC_COUNT] = 0
        battle.user.active.boosts.clear()
Exemple #14
0
def move(battle, split_msg):
    if '[from]' in split_msg[-1] and split_msg[-1] != "[from]lockedmove":
        return

    move_name = normalize_name(split_msg[3].strip().lower())

    if is_opponent(battle, split_msg):
        side = battle.opponent
        pkmn = battle.opponent.active
    else:
        side = battle.user
        pkmn = battle.user.active

    # remove volatile status if they have it
    # this is for preparation moves like Phantom Force
    if move_name in pkmn.volatile_statuses:
        logger.debug("Removing volatile status {} from {}".format(
            move_name, pkmn.name))
        pkmn.volatile_statuses.remove(move_name)

    # add the move to it's moves if it hasn't been seen
    # decrement the PP by one
    # if the move is unknown, do nothing
    move_object = pkmn.get_move(move_name)
    if move_object is None:
        new_move = pkmn.add_move(move_name)
        if new_move is not None:
            new_move.current_pp -= 1
    else:
        move_object.current_pp -= 1
        logger.debug(
            "{} already has the move {}. Decrementing the PP by 1".format(
                pkmn.name, move_name))

    # if this pokemon used two different moves without switching,
    # set a flag to signify that it cannot have a choice item
    if (is_opponent(battle, split_msg)
            and side.last_used_move.pokemon_name == side.active.name
            and side.last_used_move.move != move_name):
        logger.debug(
            "{} used two different moves - it cannot have a choice item".
            format(pkmn.name))
        pkmn.can_have_choice_item = False
        if pkmn.item in constants.CHOICE_ITEMS:
            logger.warning(
                "{} has a choice item, but used two different moves - setting it's item to UNKNOWN"
                .format(pkmn.name))
            pkmn.item = constants.UNKNOWN_ITEM

    # if the opponent uses a boosting status move, they cannot have a choice item
    # this COULD be set for any status move, but some pkmn uncommonly run things like specs + wisp
    try:
        if constants.BOOSTS in all_move_json[move_name] and all_move_json[
                move_name][constants.CATEGORY] == constants.STATUS:
            logger.debug(
                "{} used a boosting status-move. Setting can_have_choice_item to False"
                .format(pkmn.name))
            pkmn.can_have_choice_item = False
    except KeyError:
        pass

    try:
        if all_move_json[move_name][constants.CATEGORY] == constants.STATUS:
            logger.debug(
                "{} used a status-move. Setting can_have_assultvest to False".
                format(pkmn.name))
            pkmn.can_have_assaultvest = False
    except KeyError:
        pass

    try:
        category = all_move_json[move_name][constants.CATEGORY]
        logger.debug("Setting {}'s last used move: {}".format(
            pkmn.name, move_name))
        side.last_used_move = LastUsedMove(pokemon_name=pkmn.name,
                                           move=move_name,
                                           turn=battle.turn)
    except KeyError:
        category = None
        side.last_used_move = LastUsedMove(pokemon_name=pkmn.name,
                                           move=constants.DO_NOTHING_MOVE,
                                           turn=battle.turn)

    # if this pokemon used a damaging move, eliminate the possibility of it having a lifeorb
    # the lifeorb will reveal itself if it has it
    if category in constants.DAMAGING_CATEGORIES and not any([
            normalize_name(a) in ['sheerforce', 'magicguard']
            for a in pokedex[pkmn.name][constants.ABILITIES].values()
    ]):
        logger.debug(
            "{} used a damaging move - not guessing lifeorb anymore".format(
                pkmn.name))
        pkmn.can_have_life_orb = False

    # there is nothing special in the protocol for "wish" - it must be extracted here
    if move_name == constants.WISH and 'still' not in split_msg[4]:
        logger.debug(
            "{} used wish - expecting {} health of recovery next turn".format(
                side.active.name, side.active.max_hp / 2))
        side.wish = (2, side.active.max_hp / 2)