def test_can_add_round(self):
        """
        Test that:
        1. We have not exceeded the total rounds for this battle
        2. All combatants are alive
        3. No combatant can attack the same target twice in a row
        """
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger, total_rounds=1)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=True, level=99)
        unit_omega = self._make_unit(is_player=True, level=13)

        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        # Make sure battle was added
        battlemaster.add_battle(battle=battle)

        # Target's Scissors cut Attacker's Paper
        attacker_weapon = self._make_item(item_type="lizard")
        target_weapon = self._make_item(item_type="spock")

        unit_charlie.equip_item(item=attacker_weapon)
        unit_omega.equip_item(item=target_weapon)

        """
        Sunny day scenario
        """
        can_add_round = battle.can_add_round(attacker=unit_charlie,
                                             target=unit_omega)

        self.assertTrue(can_add_round)

        """
        Test that we cannot exceed total rounds
        """
        dungeon = self._make_dungeon()
        battle.start_round(battle=battle,
                           ircutils="quux",
                           ircmsgs="quux",
                           irc="quux",
                           dungeon=dungeon)

        self.assertEqual(len(battle.rounds), 1)

        # Swap combatant order so it is someone else's turn
        battle.combatants = list(reversed(battle.combatants))

        cannot_exceed_rounds_error = battle.can_add_round(attacker=unit_charlie,
                                                          target=unit_omega)

        self.assertEqual(cannot_exceed_rounds_error, "Cannot add round: maximum rounds reached.")
    def test_cannot_add_dead_combatants(self):
        combatant_1 = self._make_unit(level=13)
        combatant_2 = self._make_unit(level=13)
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        combatant_1.kill()

        try:
            battle.add_combatant(combatant_1)
        except InvalidCombatantException:
            battle.add_combatant(combatant_2)
            self.assertEqual(len(battle.combatants), 1)
    def test_start_round(self):
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=True, level=13)
        unit_omega = self._make_unit(is_player=True, level=13)

        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        # Make sure battle was added
        battlemaster.add_battle(battle=battle)

        # Lizard poisons Spock
        attacker_weapon = self._make_item(item_type="lizard")
        target_weapon = self._make_item(item_type="spock")

        unit_charlie.equip_item(item=attacker_weapon)
        unit_omega.equip_item(item=target_weapon)
        dungeon = self._make_dungeon()

        battle.start_round(battle=battle,
                           irc="quux",
                           ircmsgs=ircmsgs,
                           dungeon=dungeon,
                           ircutils=ircutils)

        self.assertFalse(unit_omega.has_full_hp())
        self.assertTrue(unit_charlie.has_full_hp())
        self.assertTrue(len(battle.rounds), 2)
    def test_add_battle(self):
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=True, level=13)
        unit_omega = self._make_unit(is_player=True, level=13)

        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        # Make sure battle was added
        battlemaster.add_battle(battle=battle)

        attacker_weapon = self._make_item(item_type="lizard")
        target_weapon = self._make_item(item_type="spock")

        unit_charlie.equip_item(item=attacker_weapon)
        unit_omega.equip_item(item=target_weapon)

        hit_info = unit_charlie.attack(target=unit_omega)

        battle.add_round(attacker=unit_charlie,
                         target=unit_omega,
                         hit_info=hit_info)

        self.assertEqual(len(battle.rounds), 1)
    def test_not_your_turn(self):
        """
        Unit should not be able to attack twice in a row
        """
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=False, level=99)
        unit_omega = self._make_unit(is_player=False, level=13)

        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        # Make sure battle was added
        battlemaster.add_battle(battle=battle)

        # Target's Scissors cut Attacker's Paper
        attacker_weapon = self._make_item(item_type="lizard")
        target_weapon = self._make_item(item_type="spock")

        unit_charlie.equip_item(item=attacker_weapon)
        unit_omega.equip_item(item=target_weapon)

        dungeon = self._make_dungeon()

        battle.start_round(battle=battle,
                           irc="quux",
                           ircmsgs="foo",
                           dungeon=dungeon,
                           ircutils="quux")

        """
        unit_charle's Lizard poisons unit_omega's Spock
        """
        self.assertFalse(unit_omega.has_full_hp())
        self.assertTrue(unit_charlie.has_full_hp())
        self.assertTrue(len(battle.rounds), 2)

        """
        Try to attack again (should work since this is not pvp)
        """
        can_start_reason = battle.start_round(battle=battle,
                                              irc="quux",
                                              ircmsgs="foo",
                                              dungeon=dungeon,
                                              ircutils="quux")

        self.assertTrue(can_start_reason)
        self.assertTrue(len(battle.rounds), 3)
    def test_cannot_battle_unit_in_combat(self):
        """
        Units should not be able to start a battle
        if either of them are currently engaged in
        a battle.
        """
        unit_alpha = self._make_unit(level=13)
        unit_bravo = self._make_unit(level=13)
        unit_delta = self._make_unit(level=13)

        # Engage first two targets in battle
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger, total_rounds=2)

        battle.add_combatant(unit_alpha)
        battle.add_combatant(unit_bravo)

        self.assertEqual(len(battle.combatants), 2)

        battlemaster = Battlemaster()
        battlemaster.add_battle(battle=battle)

        """
        Make sure we can't add a combatant in battle to
        another battle simultaneously
        """
        with LogCapture():
            logger = logging.getLogger()
            another_battle = Battle(log=logger)

        another_battle.add_combatant(unit_alpha)
        another_battle.add_combatant(unit_bravo)
        another_battle.add_combatant(unit_delta)

        """
        Attempting to do this should not work
        because two of the combatants are in battle.
        """
        battlemaster.add_battle(battle=another_battle)
        self.assertEqual(len(battlemaster.battles), 1)
    def test_target_retaliation(self):
        """
        Tests the the following use case:
        1. Attacker strikes
        2. Target is equipped with a counter item type
        3. Attacker should miss and then take damage from
           the target unit's attack
        """
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=True, level=13)
        unit_omega = self._make_unit(is_player=True, level=13)

        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        # Make sure battle was added
        battlemaster.add_battle(battle=battle)

        # Target's Scissors cut Attacker's Paper
        attacker_weapon = self._make_item(item_type="paper")
        target_weapon = self._make_item(item_type="scissors")

        unit_charlie.equip_item(item=attacker_weapon)
        unit_omega.equip_item(item=target_weapon)

        dungeon = self._make_dungeon()

        battle.start_round(battle=battle,
                           irc="quux",
                           ircmsgs="foo",
                           dungeon=dungeon,
                           ircutils="quux")

        """
        Since Unit Omega had scissors equipped they should
        have dealt damage to Unit Charlie
        """
        self.assertFalse(unit_charlie.has_full_hp())
        self.assertTrue(unit_omega.has_full_hp())
        self.assertTrue(len(battle.rounds), 2)
    def test_battle_add_challenge(self):
        """
        In order to engage in combat, the unit must consent
        to a challenge. NPCs should accept automatically; an
        attack with an NPC target generates a challenge.

        If NPC:
        - issue challenge immediately adds challenge

        if PC:
        - issue challenge adds to battlemaster.challenges
        and accepting adds hostile combatant to target

        A battle ending or a unit dying should clear
        hostile combatants
        """
        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battlemaster = Battlemaster()

        unit_charlie = self._make_unit(is_player=True, level=13)
        unit_omega = self._make_unit(is_player=True, level=13)

        """
        Could adding a combatant automatically issue a challenge?
        """
        battle.add_combatant(combatant=unit_charlie)
        battle.add_combatant(combatant=unit_omega)

        self.assertEqual(len(battle.combatants), 2, "Failed to add combatants")

        """
        The battlemaster issues a challenge on behalf of
        unit_charlie!
        """
        battlemaster.issue_challenge(attacker=unit_charlie,
                                     target=unit_omega)

        self.assertEqual(len(battlemaster.challenges), 1)

        """
        After the challenge has been issued, verify that
        the Battlemaster has recorded that
        """
        has_challenged = \
            battlemaster.has_accepted_challenge(attacker=unit_charlie,
                                                target=unit_omega)

        self.assertFalse(has_challenged, "Failed to issue challenge")

        # Attempt to accept challenge
        battlemaster.accept_challenge_from_target(attacker=unit_charlie,
                                                  target=unit_omega)

        accepted_challenge = \
            battlemaster.has_accepted_challenge(attacker=unit_charlie,
                                                target=unit_omega)

        self.assertTrue(accepted_challenge, "Failed to accept challenge")
    def test_add_battle_with_rounds(self):
        combatant_1 = self._make_unit(level=13, is_player=False)
        combatant_2 = self._make_unit(level=13, is_player=False)

        with LogCapture():
            logger = logging.getLogger()
            battle = Battle(log=logger)

        battle.add_combatant(combatant_1)
        battle.add_combatant(combatant_2)

        self.assertEqual(len(battle.combatants), 2)

        battlemaster = Battlemaster()
        battlemaster.add_battle(battle=battle)

        self.assertEqual(len(battlemaster.battles), 1)

        actual_1 = battlemaster.get_battle_by_combatant(combatant=combatant_1)
        self.assertIsNotNone(actual_1)
        self.assertEqual(battle, actual_1)

        actual_2 = battlemaster.get_battle_by_combatant(combatant=combatant_2)
        self.assertIsNotNone(actual_2)
        self.assertEqual(battle, actual_2)

        self.assertTrue(combatant_1.is_alive())
        self.assertTrue(combatant_2.is_alive())

        """
        Round 1
        """
        attacker_weapon = self._make_item(item_type="rock")
        target_weapon = self._make_item(item_type="scissors")

        combatant_1.equip_item(item=attacker_weapon)
        combatant_2.equip_item(item=target_weapon)

        dungeon = self._make_dungeon()
        battle.start_round(battle=battle,
                           irc="quux",
                           ircutils="quux",
                           ircmsgs="quux",
                           dungeon=dungeon)

        self.assertEqual(len(battle.rounds), 1)

        rounds_won_for_combatant_1 = battle.get_rounds_won(
            combatant=combatant_1)
        rounds_won_for_combatant_2 = battle.get_rounds_won(
            combatant=combatant_2)

        self.assertEqual(rounds_won_for_combatant_1, 1)
        self.assertEqual(rounds_won_for_combatant_2, 0)

        """
        Round 2
        """
        round_2_attacker_weapon = self._make_item(item_type="paper")
        round_2_target_weapon = self._make_item(item_type="rock")

        combatant_2.equip_item(item=round_2_attacker_weapon)
        combatant_1.equip_item(item=round_2_target_weapon)

        battle.combatants = list(reversed(battle.combatants))

        battle.start_round(battle=battle,
                           irc="quux",
                           ircutils="quux",
                           ircmsgs="quux",
                           dungeon=dungeon)

        self.assertEqual(len(battle.rounds), 2)

        rounds_won_for_combatant_1 = battle.get_rounds_won(
            combatant=combatant_1)
        rounds_won_for_combatant_2 = battle.get_rounds_won(
            combatant=combatant_2)

        self.assertEqual(rounds_won_for_combatant_1, 1)
        self.assertEqual(rounds_won_for_combatant_2, 1)

        """
        Round 3
        """
        round_3_attacker_weapon = self._make_item(item_type="lizard")
        round_3_target_weapon = self._make_item(item_type="spock")

        combatant_1.equip_item(item=round_3_attacker_weapon)
        combatant_2.equip_item(item=round_3_target_weapon)

        battle.combatants = list(reversed(battle.combatants))

        battle.start_round(battle=battle,
                           irc="quux",
                           ircutils="quux",
                           ircmsgs="quux",
                           dungeon=dungeon)

        self.assertEqual(len(battle.rounds), 3)

        rounds_won_for_combatant_1 = battle.get_rounds_won(
            combatant=combatant_1)
        rounds_won_for_combatant_2 = battle.get_rounds_won(
            combatant=combatant_2)

        self.assertEqual(rounds_won_for_combatant_1, 2)
        self.assertEqual(rounds_won_for_combatant_2, 1)

        """
        Make sure we can't exceed max rounds
        """
        cannot_add_round_reason = battle.can_add_round(attacker=combatant_1,
                                                       target=combatant_2)
        self.assertEqual(cannot_add_round_reason, "Cannot add round: maximum rounds reached.")
        self.assertEqual(len(battle.rounds), 3)
Example #10
0
    def _start_player_battle_with_weapon(self, **kwargs):
        """
        1. Get dungeon and player
        2. Equip player with desired item type
        3. Start battle and add combatants
        4. Add round
        """
        irc = kwargs["irc"]
        player_user = kwargs["player_user"]
        target_name = kwargs["target_name"]
        weapon_type = kwargs["weapon_type"]

        dungeon_info = self._get_dungeon_and_player(irc, player_user)

        if dungeon_info is not None:
            dungeon = dungeon_info["dungeon"]
            player = dungeon_info["player"]

            target_unit = dungeon.get_living_unit_by_name(target_name)

            if target_unit is None:
                irc.error("Invalid target")
                return

            equip_ok = player.equip_item_by_type(item_type=weapon_type)

            if equip_ok is not None:
                new_battle = SpiffyBattle(log=log)
                can_start_round = new_battle.can_add_round(attacker=player,
                                                           target=target_unit)

                if can_start_round is True:
                    """
                    NPCs equip a random weapon that is not what the player
                    chose each battle. This could probably be moved somewhere
                    else. Perhaps into Battle?
                    """
                    if target_unit.is_npc:
                        target_unit.equip_random_weapon(avoid_weapon_type=weapon_type)

                    """
                    Find the last battle, or create a new one if there isn't
                    one already.
                    """
                    bm = self.SpiffyWorld.battlemaster
                    battle = bm.get_battle_by_combatant(combatant=target_unit)

                    if battle is None:
                        battle = new_battle
                        battle.add_combatant(player)
                        battle.add_combatant(target_unit)

                        added_successfully = bm.add_battle(battle=battle)

                        """
                        When a combatant is currently engaged in combat,
                        they cannot be added to another battle.
                        """
                        if added_successfully is not True:
                            irc.error(added_successfully)
                            return

                        """
                        Announce challenge accepted if this is a new
                        battle.

                        dungeon.announcer.challenge_accepted(attacker=player,
                                                             target=target_unit)
                        """

                    battle.start_round(battle=battle,
                                       irc=irc,
                                       ircmsgs=ircmsgs,
                                       dungeon=dungeon,
                                       ircutils=ircutils)

                else:
                    formatted_error \
                        = "Cannot start round {} vs {} because {}".format(player,
                                                                          target_unit,
                                                                          can_start_round)
                    log.error(formatted_error)
                    irc.error(can_start_round)
            else:
                irc.error("You can't equip that.")
        else:
            log.error("SpiffyWorld: Player %s not found!" % player_user)
            irc.error("Player not found")