Source code for pyzork.battle

from .utils import get_user_input, post_output
from .actions import *

[docs]class Battle: """ The battle class does need to be subclassed unless you need a very fine grained control over how battles go. For most users, simply using this and the various parameters it makes available to you should be enough. Once you instantiated a Battle all you need to do is to call `game_loop` method to start the battle, the method will return if the player wins, if not it will raise EndGame. Parameters ------------ player : Player The player fighting enemies : List[Enemy] The list of enemies for the player to fight location : Optional[Location] Where the player is fighting, this is optional in the case that the list of enemies is form this location and it needs to be updated once they get killed off. priorities : Optional[Callable[[Battle], Callable[]]: Optional callable which determines in what order all the entities in the battle take turn. Attributes ----------- player : Player The player in the battle alive : List[NPC] The list of enemies still alive dead : List[NPC] The list of NPCS that have died turn : int The number of turns that have passed. """ def __init__(self, **kwargs): self.player = kwargs.pop("player") enemies = kwargs.pop("enemies") self.alive = [x for x in enemies if x.is_alive()] self.location = kwargs.get("location") self.priorities = kwargs.get("priorities", self.priorities) self.turn = 0 self.dead = [x for x in enemies if not x.is_alive()]
[docs] def remove_dead(self, index : int): """Remove a dead enemy from the list of living enemies and grant experience to the player Parameters ----------- index : int Index of the enemy to remove """ dead = self.alive.pop(index) self.player.gain_experience(dead.experience_granted(self.player)) self.dead.append(dead)
[docs] def priorities(self): """Overwritable method to determine in what order all the entities involved in this battle go. This function must return a list of entities which have a `battle_logic` method implmenented. Returns --------- List[Union[Player, Enemy]] The list of turn entities. """ return [self.player, *self.alive]
[docs] def win_condition(self) -> bool: """You can override this function to change the win condition of the battle by default winning the battle requires that the player still be alive and that all enemies have been wiped out. Returns -------- bool True if the battle has been won, false if it's still going. If you need to interupt the battle without it resulting in a victory you will need to raise an error and catch it in the handlers """ return not (self.player.is_alive() and self.alive)
[docs] def battle_loop(self): """Heart of the battle system. Call this to start the battle""" while not self.win_condition(): post_output(f"You are attacked by {self.alive}") for entity in self.priorities(): entity.battle_logic(self) self.end_turn() if not self.location is None: self.location.update_alive() post_output("You've killed all the enemies!")
[docs] def end_turn(self): """Increments the turns, remove dead stuff and decrement duration of modifiers""" self.turn += 1 self.player.end_turn() for index, enemy in list(enumerate(self.alive)): if not enemy.is_alive(): self.remove_dead(index) for enemy in self.alive: enemy.end_turn()
[docs] def player_turn(self): """Print possible options and let the user pick one through `battle_parser`""" post_output(f"- Attack an enemy with your {self.player.inventory.weapon}") post_output("- Cast an ability") post_output("- View your stats") post_output("- View your inventory") while self.battle_parser(): pass
[docs] def battle_parser(self) -> bool: """Take input of the user and parse it against a set of possible actions Returns -------- bool Whether this actions counts as taking a turn. If the action counts as taking a turn then performing it will end the player's turn and move onto the rest of the priorities. """ choice = get_user_input().lower() if target := attack_parser(choice, self): self.player.do_attack(target) return False elif reply := use_ability_parser(choice, self): self.player.use_ability(reply[1], reply[0]) return False elif reply := use_item_parser(choice, self): self.player.use_item_on(reply[1], reply[0]) return False elif reply := view_parser(choice): getattr(self.player, f"print_{reply}")() return True return False