Exemplo n.º 1
0
 def unsuppress_ability(self):
     assert self.ability == abilitydex['_suppressed_']
     if __debug__: log.d("Unsuppressing %s's ability", self)
     self.remove_effect(ABILITY)
     self.ability = self._suppressed_ability
     self._suppressed_ability = None
     self.set_effect(self.ability())
Exemplo n.º 2
0
def fill_in_unrevealed_attrs(foe):
    attrs, all_known = foe.known_attrs()
    if all_known:
        return

    log.d("Filling in %s's attrs: %s", foe, attrs)
    rb_index = rbstats_key(foe)

    if foe.item == itemdex['_unrevealed_']:
        probability = {rbstats.attr_probability(rb_index, item, attrs): item
                       for item in rbstats[rb_index]['item']}
        item = itemdex[probability[max(probability)]]
        foe.item = item
        if foe.is_active:
            foe.set_effect(item())
        attrs.append(item.name)

    if foe.ability == abilitydex['_unrevealed_']:
        probability = {rbstats.attr_probability(rb_index, ability, attrs): ability
                       for ability in rbstats[rb_index]['ability']}
        ability = abilitydex[probability[max(probability)]]
        foe.base_ability = foe.ability = ability
        if foe.is_active:
            foe.set_effect(ability())
        attrs.append(ability.name)

    while len(foe.moves) < 4:
        probability = {rbstats.attr_probability(rb_index, move, attrs): move
                       for move in rbstats[rb_index]['moves'] if not movedex[move] in foe.moves}
        move = movedex[probability[max(probability)]]
        foe.moves[move] = move.max_pp
        attrs.append(move.name)

    log.d("Filled in: %s", attrs)
Exemplo n.º 3
0
    def check_accuracy(self, user, move, target):
        """
        Return FAIL if the move misses.
        An accuracy value of None means to skip the accuracy check, i.e. it always hits.
        """
        accuracy = move.accuracy
        accuracy = user.accumulate_effect('on_accuracy', user, move, target, self, accuracy)
        accuracy = target.accumulate_effect('on_foe_accuracy', user, move, target, self, accuracy)
        if accuracy is None:
            return

        boost_factor = (1.0, 4.0/3.0, 5.0/3.0, 2.0, 7.0/3.0, 8.0/3.0, 3.0)
        if not move.ignore_accuracy_boosts:
            acc_boost = user.boosts['acc']
            if acc_boost > 0:
                accuracy *= boost_factor[acc_boost]
            elif acc_boost < 0:
                accuracy /= boost_factor[-acc_boost]

        if not move.ignore_evasion_boosts:
            evn_boost = target.boosts['evn']
            if evn_boost > 0:
                accuracy /= boost_factor[evn_boost]
            elif evn_boost < 0:
                accuracy *= boost_factor[-evn_boost]

        if __debug__: log.d('Using accuracy of %s', accuracy)
        if random.randrange(100) >= int(accuracy):
            if __debug__: log.i('But it missed!')
            return FAIL
Exemplo n.º 4
0
 def on_break_mold(self, target, battle):
     if target.ability.name in MOLDS:
         self.suppressed = True
         target.suppress_ability(battle)
         if __debug__: log.d("%s's %s was suppressed by moldbreaker", target, target.ability)
     else:
         self.suppressed = False
Exemplo n.º 5
0
 def on_modify_base_power(self, user, move, target, battle, base_power):
     if (battle.battlefield.weather is Weather.SANDSTORM and
         move.type in (Type.ROCK, Type.GROUND, Type.STEEL)
     ):
         if __debug__: log.d('%s was boosted by SandForce!', move)
         return base_power * 1.3
     return base_power
Exemplo n.º 6
0
    def fast_use_move(self, user, move):
        """
        Fast path optimization out of self.use_move for moves not targeting an opponent
        (move.targets_user or move.targets_field). Replaces try_move_hit and move_hit and allows
        them to skip (if target is None) checks.

        Specifically skips on_foe_try_hit, {immunity,accuracy,multihit,substitute} checks,
        calculate_damage, drain check, move.target_status, move.secondary_effects,
        move.on_move_fail, move.on_after_move_secondary.
        """
        if __debug__: log.d('%s: Fast path', move)
        if move.check_success(user, None, self) is FAIL:
            if __debug__: log.i('(check_success) But it failed')
            return FAIL

        user.damage_done_this_turn = 0

        if move.user_boosts is not None:
            if user.apply_boosts(move.user_boosts, True) is FAIL:
                if __debug__: log.i('(apply_boosts) But it failed')
                return FAIL

        if move.on_success(user, None, self) is FAIL:
            if __debug__: log.i('(on_success) But it failed')
            return FAIL

        if not move.calls_other_moves: # don't override switch moves called via copycat/sleeptalk
            user.must_switch = move.switch_user

        if (user.hp == 0 or move.selfdestruct) and not user.status is Status.FNT:
            if __debug__: log.d('User has no HP after using move, fainting')
            self.faint(user, Cause.SELFDESTRUCT, move)
Exemplo n.º 7
0
    def on_start(self, pokemon, battle):
        foe = battle.get_foe(pokemon)
        if foe is None:
            if __debug__: log.d("%s's Imposter: couldn't transform", pokemon)
            return FAIL

        if pokemon.transform_into(foe, battle) is not FAIL:
            pokemon.set_effect(effects.Transformed())
Exemplo n.º 8
0
    def on_get_move_choices(self, pokemon, moves):
        if self.move not in pokemon.moves:
            pokemon.remove_effect(Volatile.CHOICELOCK)
            if __debug__: log.d("%s doesn't have the choiced move %s, removing choicelock",
                                pokemon, self.move)
            return moves

        if __debug__: log.d('%s is choicelocked into %s', pokemon, self.move)
        return [self.move] if self.move in moves else []
Exemplo n.º 9
0
    def remove_effect(self, source, _=None):
        effect = self._effect_index.pop(source, None)
        if effect is None:
            if __debug__: log.d("Tried to remove nonexistent %s from side %d",
                                source, self.index)
            return

        self._remove_handlers(effect)
        if __debug__: log.i('Removed %s from side %d', effect, self.index)
Exemplo n.º 10
0
 def cure_status(self):
     if self.status in (None, Status.FNT):
         if __debug__: log.d("Tried to cure %s's status but it was %s", self, self.status)
     else:
         if __debug__: log.i("%s's status (%s) was cured", self, self.status)
         self.remove_effect(self.status)
         self.status = None
         self.is_resting = False
         self.turns_slept = None
Exemplo n.º 11
0
    def remove_effect(self, source, _=None):
        effect = self._effect_index.pop(source, None)
        if effect is None:
            if __debug__: log.d("Tried to remove nonexistent %s from battlefield", source)
            return
        self._remove_handlers(effect)

        if source in Weather.values:
            self._weather = None
        if __debug__: log.i('Removed %s from battlefield', effect)
Exemplo n.º 12
0
    def set_effect(self, effect, override_immunity=False):
        assert not self.is_fainted()

        if effect.source in self._effect_index:
            if __debug__: log.d('Tried to set effect %s but %s already has it', effect, self)
            return FAIL

        if not override_immunity and self.is_immune_to(effect.source):
            if __debug__: log.i('%s is immune to %s!', self, effect.source)
            return FAIL

        self._effect_index[effect.source] = effect
        self._set_handlers(effect)

        if __debug__: log.i('Set effect %s on %s', effect, self)
Exemplo n.º 13
0
    def activate_effect(self, name, *args, **kwargs):
        """
        Call all bound handlers for the named effect type, with *args as the handler method's
        arguments. Handlers are already in sorted priority order, if applicable.

        When failfast is passed as a keyword arg, bail out and return FAIL as soon as any handler
        returns FAIL.
        """
        failfast = kwargs.get('failfast', False)
        for effect in self.effect_handlers[name][:]:
            if __debug__: log.d('effect %s of %r activated', name, effect.__self__)
            rv = effect(*args)
            if failfast and rv is FAIL:
                if __debug__: log.d('Effect %s was failed by %r', name, effect.__self__)
                return FAIL
Exemplo n.º 14
0
def get_balancing_types(types):
    votes = EMPTY_COUNTER.copy()
    for type in types:
        votes[type] -= 100
        for other_type in COMPLEMENT[type]:
            votes[other_type] += 1

    sorted_votes = votes.most_common()
    log.d("votes=%s", [(k, v) for k, v in sorted_votes if v != 0])
    max_votes = sorted_votes[0][1]
    i = -1
    for i, item in enumerate(sorted_votes):
        if max_votes - item[1] > 1:
            break
    return [vote[0] for vote in sorted_votes[:i]]
Exemplo n.º 15
0
    def force_random_switch(self, pokemon, forcer):
        if (pokemon.is_fainted() or
            forcer.is_fainted() or
            pokemon.ability.name == 'suctioncups'
        ):
            return FAIL

        team_members = pokemon.get_switch_choices(forced=True)
        if team_members:
            incoming = random.choice(team_members)
            if __debug__: log.d('Force switching %s for %s', pokemon, incoming)
            self.run_switch(pokemon, incoming)
            forcer.get_effect(ABILITY).on_break_mold(incoming, self)
            self.post_switch_in(incoming)
        elif __debug__:
            log.i('Tried to force random switch; %s has no remaining teammates', pokemon)
Exemplo n.º 16
0
    def accumulate_effect(self, name, *args, **kwargs):
        """
        Call all bound handlers for the named effect type, with *args as the handler method's
        arguments. The argument in the last position, args[-1], is the accumulator variable and will
        be modified and returned.

        Failfast works as for self.activate_effect
        """
        failfast = kwargs.get('failfast', False)
        accumulator = args[-1]
        for effect in self.effect_handlers[name][:]:
            if __debug__: log.d('effect %s of %r activated', name, effect.__self__)
            accumulator = effect(*(args[:-1] + (accumulator,)))
            if failfast and accumulator is FAIL:
                return FAIL
        return accumulator
Exemplo n.º 17
0
    def run_queued_events(self):
        while self.event_queue:
            if __debug__: log.d('Event Queue: %r', self.event_queue)
            if __debug__: log.d('Next event: %s', self.event_queue[-1])
            event = self.event_queue.pop()
            event.run_event(self, self.event_queue)
            if event.type is not Decision.SWITCH:
                self.run_update()

            for side in self.battlefield.sides:
                if (side.active_pokemon is not None and
                    side.active_pokemon.must_switch and # e.g. from voltswitch
                    side.remaining_pokemon_on_bench > 0
                ):
                    self.run_must_switch(side)

            self.resolve_faint_queue()
Exemplo n.º 18
0
    def change_ability(self, new_ability, battle):
        """
        Change this pokemon's ability. This effect will only last while the pokemon is active.
        This pokemon's original ability remains saved in self.base_ability.
        """
        assert self.is_active, "Tried to change inactive pokemon's ability"
        assert issubclass(new_ability, abilities.BaseAbility)

        if ((new_ability.name in ('illusion', 'stancechange', 'multitype') or
             self.ability.name in ('stancechange', 'multitype'))):
            if __debug__: log.d("Failed to change %s's %s to %s", self, self.ability, new_ability)
            return FAIL

        self.remove_effect(ABILITY, battle)
        self.ability = new_ability
        self.set_effect(new_ability())
        self.get_effect(ABILITY).start(self, battle)
Exemplo n.º 19
0
def create_foe_for_rollout(foe_side):
    foe_team = [foe for foe in foe_side.team if foe.name != UNREVEALED]
    foe_types = filter(None, [type for foe in foe_team for type in foe.types])
    allow_mega = not any(foe.item is not None and foe.item.is_mega_stone for foe in foe_team)
    name = get_balancing_pokemon(foe_types)

    stats = rbstats[name]
    level = max(stats['level'], key=stats['level'].get) if allow_mega else max(stats['level'])
    if allow_mega:
        attrs = max(stats['sets'], key=stats['sets'].get)
    else:
        attrs = next(attrs for attrs, _ in stats['sets'].most_common()
                     if not itemdex[attrs[5]].is_mega_stone)
    moves = [movedex[move] for move in attrs[:4]]
    ability = abilitydex[attrs[4]]
    item = itemdex[attrs[5]]
    pokemon = BattlePokemon(pokedex[name], level, moves, ability, item, side=foe_side)

    log.d("Created foe: %s (%s, %s, %s)", pokemon, moves, ability, item)
    return pokemon
Exemplo n.º 20
0
    def _use_move(self, user, move, target):
        """ Return value not used (except for testing) """
        assert not user.is_fainted()
        assert user.is_active
        if __debug__: log.i('%s used %s! (target=%s)', user, move, target)

        # copy the move, so that modify_move doesn't modify the global copy in movedex
        move = move.__class__()

        move.on_modify_move(user, target, self)
        user.activate_effect('on_modify_move', move, user, self)
        if target is not None:
            target.activate_effect('on_modify_foe_move', move, user, self)

        if move.targets_user or move.targets_field:
            return self.fast_use_move(user, move) # fast path for moves not targeting opponent

        if target is None or target.is_fainted():
            if __debug__: log.i('But it failed: No target')
            if move.selfdestruct:
                self.faint(user, Cause.SELFDESTRUCT, move)
            return FAIL

        damage = self.try_move_hit(user, move, target)

        if (user.hp == 0 or move.selfdestruct) and not user.status is Status.FNT:
            if __debug__: log.d('User has no HP after using move, fainting')
            self.faint(user, Cause.SELFDESTRUCT, move)

        if damage is FAIL:
            if __debug__:
                if not user.has_effect(Volatile.TWOTURNMOVE):
                    log.i('%s: But it failed', move)
            move.on_move_fail(user, self)
            return FAIL

        if not user.has_effect(Volatile.SHEERFORCE):
            target.activate_effect('on_after_foe_move_secondary', user, move, target, self)
            user.activate_effect('on_after_move_secondary', user, move, target, self)

        return damage # for testing only
Exemplo n.º 21
0
    def apply_secondary_effect(self, pokemon, s_effect, user):
        if (random.randrange(100) >= s_effect.chance or
            pokemon is None or
            pokemon.is_fainted() or
            (pokemon.ability is abilitydex['shielddust'] and not s_effect.affects_user)):
            return

        if __debug__: log.d('Applying %s to %s', s_effect, pokemon)

        if s_effect.boosts is not None:
            pokemon.apply_boosts(s_effect.boosts, s_effect.affects_user)
        elif s_effect.status is not None:
            self.set_status(pokemon, s_effect.status, user)
        elif s_effect.volatile is Volatile.FLINCH:
            pokemon.set_effect(effects.Flinch())
        elif s_effect.volatile is Volatile.CONFUSE:
            pokemon.confuse(user.ability is abilitydex['infiltrator'])
        elif s_effect.callback is not None:
            s_effect.callback(pokemon, user, self)
        else:
            assert False, 'Tried to apply secondary effect with no boosts, volatile, or status'
Exemplo n.º 22
0
    def remove_effect(self, source, battle=None, force=False):
        """
        `battle` must be passed if there is a possibility that `source`'s effect has an on_end
        method that uses battle.

        `battle` may be omitted if `source` is known to be a move or status, but must be included
        for abilities in general.

        Return True if effect was removed
        """
        effect = self._effect_index.pop(source, None)
        if effect is None:
            if __debug__: log.d("Trying to remove %s from %s, but it wasn't found!", source, self)
            return False
        self._remove_handlers(effect)

        if __debug__: log.i('Removed %s from %s', effect, self)
        if not force and 'on_end' in effect.handler_names:
            effect.on_end(self, battle)
        if source is self.status:
            self.status = None

        return True
Exemplo n.º 23
0
    def known_attrs(self):
        """
        Return the names of the known move/item/ability attributes of this foe pokemon:
        [moves..., ability, item]

        Do not return the base_ability of a mega/primal pokemon, since rbstats only tracks the
        base_ability of the pre-formechange pokemon, so lookups will fail using the post-change
        ability. This doesn't reduce the accuracy of lookups, since if the pokemon is mega/primal
        this is seen uniquely in the item.
        """
        attrs = [move.name for move in self.moves if move.type != Type.NOTYPE]
        if self.original_item != itemdex['_unrevealed_']:
            attrs.append(self.original_item.name)
        if (self.base_ability != abilitydex['_unrevealed_'] and not
            (self.is_mega or self.name.endswith('primal'))):
            attrs.append(self.base_ability.name)
        log.d("attrs: %s", attrs)

        all_known = (len(attrs) == 6 or
                     (len(attrs) == 5 and (self.is_mega or self.name.endswith('primal'))) or
                     (len(attrs) == 3 and self.base_species == 'ditto'))

        return attrs, all_known
Exemplo n.º 24
0
    def move_hit(self, user, move, target):
        assert target is not None

        user.activate_effect('on_move_hit', user, move, self)

        substitute = target.get_effect(Volatile.SUBSTITUTE)
        if substitute is not None:
            result = substitute.on_hit_substitute(user, move, target, self)
            if result is not None:
                if __debug__: log.d('Hit substitute: result=%s', result)
                return result
            elif __debug__: log.d('Bypassed substitute')

        damage = self.calculate_damage(user, move, target)
        if damage is FAIL:
            return FAIL

        if damage is not None:
            damage = self.damage(target, damage, Cause.MOVE, move, user, move.drain)
            if damage is FAIL:
                if __debug__: log.i('Move failed in Battle.damage: returned %s', damage)
                return FAIL

        user.damage_done_this_turn = damage

        if move.target_status is not None:
            if self.set_status(target, move.target_status, user) is FAIL:
                return FAIL     # all target_status moves do nothing else, so fail fast

        if move.user_boosts is not None and not user.is_fainted():
            user.apply_boosts(move.user_boosts, True)

        user.activate_effect('on_move_success', user, move, target)

        if move.on_success(user, target, self) is FAIL:
            if __debug__: log.i('Move "%s" failed in on_success', move)
            return FAIL

        target = self.get_foe(user) # roar, etc. could have changed the active foe

        if target is not None:
            target.activate_effect('on_after_foe_hit', user, move, target, self)

        for s_effect in move.secondary_effects:
            self.apply_secondary_effect(user if s_effect.affects_user else target,
                                        s_effect, user)

        user.must_switch = move.switch_user

        if __debug__: log.d('returning damage=%s', damage)
        return damage
Exemplo n.º 25
0
 def on_modify_move(self, move, user, battle):
     if move.accuracy is not None and move.category is MoveCategory.PHYSICAL:
         move.accuracy *= 0.8
         if __debug__: log.d("%s's accuracy decreased to %s by Hustle",
                             move, move.accuracy)
Exemplo n.º 26
0
 def on_modify_damage(self, user, move, effectiveness, damage):
     if __debug__: log.d("%s was boosted by %s's LifeOrb", move, user)
     return damage * 1.3
Exemplo n.º 27
0
 def on_modify_spe(self, pokemon, battle, spe):
     if battle.battlefield.weather is Weather.SANDSTORM:
         if __debug__: log.d("%s's SandRush boosted its speed!", pokemon)
         return spe * 2
     return spe
Exemplo n.º 28
0
 def on_unbreak_mold(self, target):
     if self.suppressed and target is not None:
         target.unsuppress_ability()
         if __debug__: log.d("%s's %s was restored", target, target.ability)
     self.suppressed = False
Exemplo n.º 29
0
 def on_modify_spe(self, pokemon, battle, spe):
     if pokemon.status is not None:
         if __debug__: log.d("%s's QuickFeet boosted its speed!", pokemon)
         return spe * 1.5
     return spe
Exemplo n.º 30
0
 def on_get_immunity(self, thing):
     if thing in (Weather.HAIL, Weather.SANDSTORM, POWDER):
         if __debug__: log.d('%s damage prevented by Overcoat', thing)
         return True