Пример #1
0
    def run(self):
        self.assert_state('new')

        self.message.BattleStart()

        sendouts = []
        exclude = []
        for side in self.sides:
            for spot in side.spots:
                monster = spot.trainer.get_first_inactive_monster(
                        exclude=exclude)
                sendouts.append((spot, monster))
                self.release_monster(spot, monster)
        self.sort_by_speed(
                sendouts,
                key=lambda x: x[1].stats.speed,
                reverse=True,
            )
        for spot, mon in sendouts:
            Effect.send_out(spot.battler)

        self.state = 'waiting'

        self.ask_for_commands()
        self.command_loop()
Пример #2
0
 def roll_accuracy(self, hit):
     if hit.accuracy is None or Effect.ensure_hit(hit):
         return True
     else:
         hit.accuracy = hit.accuracy * hit.user.stats.accuracy / hit.target.stats.evasion
         # XXX: Is this the correct rounding?
         hit.accuracy = Fraction(int(hit.accuracy * 100), 100)
         accuracy = Effect.modify_accuracy(hit, hit.accuracy)
         return self.field.flip_coin(accuracy, "Determine hit")
Пример #3
0
 def do_use(self, **kwargs):
     self.field.message.UseMove(battler=self.user, moveeffect=self)
     Effect.move_used(self)
     self.targets = list(self.get_targets(**kwargs))
     self.deduct_pp()
     self.user.used_move_effects.append(self)
     hits = self.use(**kwargs)
     if hits:
         Effect.move_hits_done(self, [hit for hit in hits if hit])
     return hits
Пример #4
0
 def determine_critical_hit(self, hit):
     if Effect.prevent_critical_hit(hit):
         return False
     stage = Effect.critical_hit_stage(hit, 1)
     rate = {1: Fraction(1, 16), 2: Fraction(1, 8), 3: Fraction(1, 4), 4: Fraction(1, 3), 5: Fraction(1, 2)}[
         min(stage, 5)
     ]
     hit.is_critical = self.field.flip_coin(rate, "Determine critical hit")
     if hit.is_critical:
         return True
     else:
         return Effect.force_critical_hit(self)
Пример #5
0
    def calculate_damage(self, hit):
        damage_class = hit.damage_class
        user = hit.user
        target = hit.target

        loader = self.field.loader
        if damage_class.identifier == "physical":
            attack_stat = loader.load_stat("attack")
            defense_stat = loader.load_stat("defense")
        else:
            attack_stat = loader.load_stat("special-attack")
            defense_stat = loader.load_stat("special-defense")

        self.field.message.effectivity(hit=hit)
        if not hit.effectivity:
            return None

        hit.is_critical = hit.move_effect.determine_critical_hit(hit)
        if hit.is_critical:
            self.field.message.CriticalHit(hit=hit)
            attack = user.get_stat(attack_stat, min_change_level=0)
            defense = target.get_stat(defense_stat, max_change_level=0)
        else:
            attack = user.stats[attack_stat]
            defense = target.stats[defense_stat]

        damage = (user.level * 2 // 5 + 2) * hit.power * attack // 50 // defense

        damage = Effect.modify_move_damage(hit, damage)

        if damage < 1:
            damage = 1

        return damage
Пример #6
0
    def process_replacements(self):
        """Send out monsters to replace those that have fainted."""
        self.assert_state('waiting_replacements')

        commands = [command for command in self.commands.values()
                if command.command == 'switch']

        for command in commands:
            battler = command.battler
            spot = battler.spot
            self.switch(spot, command.replacement)

        trick_factor = Effect.speed_factor(self, 1)
        commands.sort(key=lambda c: -c.replacement.stats.speed * trick_factor)
        for command in commands:
            Effect.send_out(command.battler.spot.battler)

        self.ask_for_commands()
Пример #7
0
 def _get_effectivity(self):
     if not self.type:
         return 1
     effectivity = 1
     efficacies = self.type.damage_efficacies
     for type in self.target.types:
         efficacy, = [e for e in efficacies if e.target_type == type]
         effectivity *= Fraction(efficacy.damage_factor, 100)
     return Effect.modify_effectivity(self, effectivity)
Пример #8
0
 def key(effect):
     try:
         spot = effect.subject.spot
     except AttributeError:
         turn_order = speed = 0
     else:
         turn_order = spot.turn_order
         speed = spot.battler.stats.speed * Effect.speed_factor(spot, 1)
     return (major_tier, EndTurnOrder.tier_effect, -speed, turn_order,
             minor_tier)
Пример #9
0
    def command_allowed(self, command, ignore_pp=False):
        if command.battler.fainted and command.command != 'switch':
            return False
        if command.command == 'move':
            move = command.move
            if move is None:
                # Forced move!
                pass
            else:
                if move.kind == self.struggle:
                    # Struggle: We trust the trainer that there are no usable
                    # moves left
                    return True
                if move.pp <= 0 and not ignore_pp:
                    return False
                if Effect.prevent_move_selection(command):
                    return False
            return True
        elif command.command == 'switch':
            replacement = command.replacement
            if replacement.fainted:
                # Can't send in a fainted monster
                return False
            for battler in self.battlers:
                if command.replacement is battler.monster:
                    # Can't switch to an already active battler
                    return False
                if command in self.commands.values():
                    # Cant switch to a monster being already switched in!
                    # Note that this makes the result of command_allowed()
                    # dependent on commands already issued this turn
                    return False
            battler = command.request.battler
            if not battler or battler.fainted:
                return True
            return not Effect.prevent_switch(command)
        elif command.command == 'run':
            return self.allow_run

        raise NotImplementedError(command)
Пример #10
0
 def __init__(self, move_effect, target, **kwargs):
     self.move_effect = move_effect
     self.target = target
     self.field = move_effect.field
     self.user = move_effect.user
     self.type = move_effect.type
     self.accuracy = move_effect.accuracy
     self.damage_class = move_effect.damage_class
     self.args = kwargs
     self.effectivity = self._get_effectivity()
     if move_effect.power is None:
         self.power = None
     else:
         self.power = Effect.modify_base_power(self, move_effect.power)
Пример #11
0
    def speed_key(major_minor):
        """Decorator for end-of-turn effects.

        Sort by major tier, then the subject speed, then the minor tier
        """
        major_tier, minor_tier = major_minor
        def key(effect):
            try:
                spot = effect.subject.spot
            except AttributeError:
                turn_order = speed = 0
            else:
                turn_order = spot.turn_order
                speed = spot.battler.stats.speed * Effect.speed_factor(spot, 1)
            return (major_tier, EndTurnOrder.tier_effect, -speed, turn_order,
                    minor_tier)
        return Effect.orderkey(key)
Пример #12
0
    def handle_turn(self):
        self.assert_state('processing')

        commands = []
        for battler, command in self.commands.items():
            commands.append(command)

        self.message.TurnStart(turn=self.turn_number)
        Effect.begin_turn(self)

        self.turnCommands = commands = self.sort_commands(commands)

        self.turn_order = [c.request.spot for c in commands]

        move_effects = {}

        for command in commands:
            if command.command == 'move':
                command.move_effect = command.move.get_effect(
                        command.request.battler,
                        command.target)
                command.move_effect.begin_turn()

        for command in commands:
            battler = command.battler
            spot = battler.spot

            self.message.SubturnStart(battler=battler, turn=self.turn_number)
            if command.command == 'move':
                if not command.battler.fainted:
                    command.move_effect.attempt_use()
            elif command.command == 'switch':
                self.switch(command.request.spot, command.replacement)
                Effect.send_out(command.battler.spot.battler)
            else:
                raise NotImplementedError(command)
            self.message.SubturnEnd(battler=battler, turn=self.turn_number)
            if self.check_win():
                return

        Effect.end_turn(self)

        if self.state == 'finished' or self.check_win():
            return

        self.message.TurnEnd(turn=self.turn_number)

        # That's it for this turn!
        del self.turn_order

        if not self.ended:
            self.state = 'waiting'
            self.ask_for_commands()
Пример #13
0
 def command_sort_order(self, command):
     speed_value = command.request.battler.stats.speed
     trick_factor = Effect.speed_factor(self, 1)
     speed_sort_value = -speed_value * trick_factor
     if command.command == 'move':
         return (
                 1,
                 -command.move.priority,
                 speed_sort_value,
             )
     elif command.command == 'switch':
         # XXX: Should switch-ins be sorted by speed?
         return (
                 0,
                 speed_sort_value,
             )
     else:
         raise NotImplementedError(command.command)
Пример #14
0
 def get_stat(self, stat, min_change_level=None, max_change_level=None):
     if stat.identifier == 'hp':
         return self.monster.stats[stat]
     level = self.stat_levels[stat]
     if min_change_level is not None and level < min_change_level:
         level = min_change_level
     if max_change_level is not None and level > max_change_level:
         level = max_change_level
     if stat in self.monster.stats:
         base = self.monster.stats[stat]
         numerator = denominator = 2
         round_func = int
     else:
         base = 1
         numerator = denominator = 3
         round_func = Fraction
     if level < 0:
         denominator -= level
     elif level > 0:
         numerator += level
     value = round_func(base * Fraction(numerator, denominator))
     return Effect.modify_stat(self, value, stat)
Пример #15
0
 def do_damage(self, damage, direct=False, message_class=messages.HPChange,
             **extra_message_args):
     Effect.damage_done(self, damage)
     return -self.change_hp(-damage, direct, message_class,
             **extra_message_args)
Пример #16
0
 def withdraw(self, battler):
     if not battler.fainted:
         self.message.Withdraw(battler=battler)
     Effect.withdraw(battler)
     battler.spot.battler = None
Пример #17
0
 def attempt_hit(self, hit):
     if Effect.prevent_hit(hit):
         return None
     elif not self.roll_accuracy(hit):
         return self.miss(hit)
     return self.do_hit(hit)
Пример #18
0
 def do_hit(self, hit):
     Effect.move_hit(hit)
     return self.hit(hit)
Пример #19
0
 def do_damage(self, hit):
     hit.damage = self.calculate_damage(hit)
     if hit.damage:
         hit.damage = hit.target.do_damage(hit.damage, direct=True)
         Effect.move_damage_done(hit)
     return hit.damage
Пример #20
0
 def attempt_use(self, **kwargs):
     if Effect.prevent_use(self):
         return
     return self.do_use()
Пример #21
0
 def attempt_secondary_effect(self, hit):
     if not hit.target.fainted:
         chance = Effect.modify_secondary_chance(hit, self.secondary_effect_chance)
         if self.field.flip_coin(chance, "Attempt secondary effect"):
             self.do_secondary_effect(hit)
Пример #22
0
 def deduct_pp(self):
     if self.ppless not in self.flags:
         delta = -min(self.move.pp, Effect.pp_reduction(self, 1))
         self.move.pp += delta
         self.field.message.PPChange(move=self.move, battler=self.user, delta=delta, pp=self.move.pp, cause=self)