Ejemplo n.º 1
0
 def on_switch_in(self, pokemon, battle):
     if pokemon.is_fainted():
         if __debug__: log.w('%s fainted before HealingWish could heal it')
         return
     battle.heal(pokemon, pokemon.max_hp)
     pokemon.cure_status()
     pokemon.side.remove_effect(SideCondition.HEALINGWISH)
Ejemplo n.º 2
0
    def describe_possible_foe_moves(self, my_active, foe):
        if len(foe.moves) >= 4 or foe.base_species == 'ditto':
            return ''

        foe_index = rbstats_key(foe)

        for move in foe.moves:
            if (move.name not in rbstats.probability[foe_index]['moves'] and
                move.type != Type.NOTYPE):
                log.w('%s not in rbstats for %s: Stale showdown data?', move.name, foe)

        possible_moves = [movedex[move] for move in rbstats[foe_index]['moves']
                          if movedex[move] not in foe.moves]
        data = []
        known_attrs = [move_.name for move_ in foe.moves if move_.type != Type.NOTYPE]
        if not rbstats.possible_sets(foe_index, known_attrs):
            log.w("%s's move probabilities cannot be calculated: unexpected attribute in %s",
                  foe_index, known_attrs)
            calculate_prob = False
        else:
            calculate_prob = True

        for move in possible_moves[:]:
            if calculate_prob:
                prob = rbstats.attr_probability(foe_index, move.name, known_attrs)
                if not prob:
                    possible_moves.remove(move)
                    continue
            else:
                prob = 0.5

            dmg_range = self.calculate_damage_range(foe, move, my_active)
            data.append((move.name, prob, dmg_range))

        return sorted(data, key=lambda x: -x[1])
Ejemplo n.º 3
0
    def describe_my_moves(self, my_active, foe):
        """ :type my_active BattlePokemon """
        if not my_active.is_transformed:
            active = rbstats_key(my_active)
            for move in my_active.moves:
                if move.name not in rbstats.probability[active]['moves']:
                    log.w('%s not in rbstats for %s: Stale showdown data?', move.name, my_active)

        return [(move.name, self.calculate_damage_range(my_active, move, foe))
                for move in my_active.moves]
Ejemplo n.º 4
0
    def damage(self, pokemon, damage, cause, source=None, attacker=None, drain_pct=None):
        """
        Return FAIL or int amount of damage done.
        If the damage is caused directly by a move then source and attacker must be set.
        Draining effects (drain moves or leechseed) pass a percent of damage to drain to attacker.
        """
        if pokemon.is_fainted():
            if __debug__:
                log.w('Tried to damage fainted pokemon %s: cause: %s, source: %s, attacker: %s',
                      pokemon, cause, source, attacker)
            return 0

        assert pokemon is not attacker
        assert pokemon.side.active_pokemon is pokemon
        assert pokemon.is_active
        assert damage >= 0
        assert ((isinstance(attacker, BattlePokemon) and isinstance(source, Move)) if
                cause is Cause.MOVE else True)

        if damage == 0:
            if __debug__: log.w('Battle.damage called with damage=0') # this shouldn't happen
            return 0

        if cause is Cause.WEATHER and pokemon.is_immune_to(source):
            if __debug__: log.i('Weather immunity: %s / %s', pokemon, source)
            return 0

        if damage < 1:
            damage = 1 # always do at least 1 damage
        else:
            damage = int(damage)

        damage = pokemon.accumulate_effect('on_damage',
                                           pokemon, cause, source, self, damage, failfast=True)
        if damage is FAIL:
            return FAIL

        pokemon.hp -= damage
        if __debug__: log.i('%s took %s (%.1f%%) damage from %s: %s; hp=%d/%d' %
                            (pokemon, damage, 100*float(damage)/pokemon.max_hp, cause, source,
                             pokemon.hp, pokemon.max_hp))
        if pokemon.hp <= 0:
            damage += pokemon.hp

        if drain_pct and not attacker.is_fainted():
            self.heal(attacker, int(math.ceil(damage * drain_pct / 100.0)), cause=Cause.DRAIN,
                      foe=pokemon)

        if cause is Cause.MOVE:
            pokemon.activate_effect('on_after_move_damage', self, pokemon, damage, source, attacker)

        if pokemon.hp <= 0:
            self.faint(pokemon, cause, source, attacker)

        return damage
Ejemplo n.º 5
0
    def resolve_faint_queue(self):
        while self.faint_queue:
            pokemon = self.faint_queue.pop()
            assert pokemon.is_fainted() and pokemon.status is Status.FNT

            if pokemon.side.remaining_pokemon_on_bench == 0 and self.battlefield.win is None:
                self.battlefield.win = int(not pokemon.side.index)
                if __debug__: log.i('Side %d wins!', self.battlefield.win)

            if __debug__:
                if pokemon.effects:
                    log.w('Post-fainted pokemon has effects: %r', pokemon)
Ejemplo n.º 6
0
    def attr_probability(self, pokemon, attr, known_attrs):
        """
        Return the probability [0.0, 1.0] that pokemon has attr, given that it has [known_attrs].
        pokemon: str, attr: str, known_attrs: list<str>
        """
        attrs_counter = self[pokemon]['sets']
        possible = self.possible_sets(pokemon, known_attrs)

        if not possible:
            if __debug__:
                log.w("%s's known_attrs %s does not correspond to any known attrset in rbstats. "
                      "Cannot calculate move probabilities; returning 0.5", pokemon, known_attrs)
            return 0.5

        target_attrs = [attrset for attrset in possible if attr in attrset]

        probability = (float(sum(attrs_counter[attrset] for attrset in target_attrs)) /
                       sum(attrs_counter[attrset] for attrset in possible))
        return probability
Ejemplo n.º 7
0
    def faint(self, pokemon, cause, source=None, attacker=None):
        if pokemon.status is Status.FNT:
            if __debug__: log.w('Tried to faint %s twice!', pokemon)
            return
        pokemon.hp = 0
        pokemon.status = Status.FNT # This should be the only way to assign Status.FNT
        pokemon.side.last_fainted_on_turn = self.battlefield.turns
        pokemon.side.active_pokemon = None
        pokemon.is_active = False

        if __debug__: log.i('%s fainted: %s (source=%s)', pokemon, cause, source)
        self.faint_queue.insert(0, pokemon)

        pokemon.activate_effect('on_faint', pokemon, cause, source, self)

        if attacker is not None and not attacker.is_fainted():
            attacker.activate_effect('on_foe_faint', attacker, cause, source, pokemon, self)

        foe = self.get_foe(pokemon)
        if foe is not None:
            foe.remove_trap_effects()

        pokemon.clear_effects(self)
        pokemon.boosts = Boosts()