예제 #1
0
    def activate(self, action):
        """ gets the target location, and ensures that it is within the line of sight. It then checks
        for entities within the radius, damaging any that are close enough to hit (take note, there’s
        no exception for the player, so you can get blasted by your own fireball!). If no enemies were
        hit at all, the Impossible exception is raised, and the scroll isn’t consumed, as it would
        probably be frustrating to waste a scroll on something like a misclick. Assuming at least one
        entity was damaged, the scroll is consumed.
        """
        target_xy = action.target_xy
        consumer = action.entity

        if not self.engine.game_map.visible[target_xy]:
            raise exceptions.Impossible(
                "You cannot target an area that you cannot see.")

        targets_hit = False

        results = []
        actors = self.engine.game_map.has_comp("fighter")
        for actor in actors:
            if src.utils.distance(actor.x, actor.y, *target_xy) <= self.radius:
                action.msg += f"The {actor.name} is engulfed in a fiery explosion! "
                actor.fighter.hp -= self.damage

                if actor.fighter.is_dead():
                    results.append(DieAction(entity=actor, cause=consumer))

                targets_hit = True

        if not targets_hit:
            raise exceptions.Impossible("There are no targets in the radius.")

        self.consume()

        return results
예제 #2
0
파일: equipment.py 프로젝트: elunna/labhack
    def equip_to_slot(self, slot, item):
        """ Attempts to equip an item to a slot on the actor.
            If successful, returns a string describing what happened.
            If not, returns an empty string.
        """
        # Check if the item is equippable
        if not getattr(item, "equippable", None):
            raise exceptions.Impossible("f{item.name} is not an Equippable!")

        # Check if item's slot is valid
        # Convert the enum to a str so we can compare...
        item_slot = item.equippable.equipment_type.name

        if item_slot not in self.slots:
            raise exceptions.Impossible(
                f"The item's slot ({slot}) is not valid!")

        # Item slot must also match the provided slot.
        if item_slot != slot:
            raise exceptions.Impossible(
                f"The item's slot ({slot}) does not match the provided slot {item_slot}!"
            )

        msg = ''
        # current_item = getattr(self, slot)
        current_item = self.slots[slot]

        if current_item is not None:
            msg += self.unequip_from_slot(slot)

        # Equip the new item
        self.slots[item_slot] = item

        msg += self.equip_message(item.name)
        return msg
예제 #3
0
    def perform(self):
        """ Take the stairs, if any exist at the entity's location. """
        player_location = (self.entity.x, self.entity.y)
        stair_location = self.dungeon.current_map.upstairs_location

        if player_location == stair_location:

            # Do we have a level above us?
            if self.dungeon.dlevel == DUNGEON_TOP_LEVEL:
                raise exceptions.Impossible("Cannot go upstairs at top of dungeon!")

            self.dungeon.move_upstairs(self.entity)
            self.msg = "You ascend the stairs."
        else:
            raise exceptions.Impossible("There are no stairs here.")
예제 #4
0
    def perform(self):
        """ Removes an item from an entity's inventory and places it on the
            current game map, at the entity's coordinates.
        """
        # If the item is an equipped item, first unequip it.
        if self.entity.equipment.is_equipped(self.item):
            self.entity.equipment.toggle_equip(self.item)

        # If stackable, drop all of them
        if "stackable" in self.item:
            amount = self.item.stackable.size
        else:
            amount = 1

        result = self.entity.inventory.rm_inv_item(self.item, amount)
        result.x = self.entity.x
        result.y = self.entity.y

        if result:
            # Put it on the map
            self.entity.gamemap.add_item(result)
            if amount == 1:
                self.msg = f"You dropped a {result.name}."
            else:
                self.msg = f"You dropped {amount} {result.name}s."
        else:
            raise exceptions.Impossible(
                "You cannot drop an item you do not have!")
예제 #5
0
    def perform(self):
        """Picks up an item from the entities' current location and adds it to their inventory."""
        inventory = self.entity.inventory
        # items_on_location = self.entity.gamemap.get_items_at(self.entity.x, self.entity.y)
        items_on_location = self.entity.gamemap.filter("item",
                                                       x=self.entity.x,
                                                       y=self.entity.y)
        for item in items_on_location:
            # If stackable, pickup all of them
            if "stackable" in item:
                amount = item.stackable.size
            else:
                amount = 1

            result = self.entity.gamemap.rm_item(item)
            if result:
                result.x = -1
                result.y = -1
                letter = inventory.add_inv_item(result, amount)
            else:
                raise Exception('No result from rm_item!')

            if result.name == "money":
                self.msg = f"({letter}) - ${amount}"
            elif amount > 1:
                self.msg = f"({letter}) - {result}s"
            else:
                self.msg = f"({letter}) - {result}"
            return

        raise exceptions.Impossible("There is nothing here to pick up.")
예제 #6
0
    def activate(self, action):
        """Finds the closest actor to the consumer and deals lightning damage to that actor.
        Then consumes this consumable."""
        consumer = action.entity
        target = None
        closest_distance = self.maximum_range + 1.0

        for actor in self.engine.game_map.actors:
            if actor is not consumer and self.parent.gamemap.visible[actor.x,
                                                                     actor.y]:
                distance = src.utils.distance(consumer.x, consumer.y, actor.x,
                                              actor.y)

                if distance < closest_distance:
                    target = actor
                    closest_distance = distance

        if target:
            action.msg = f"A lighting bolt zaps the {target.name} with a roaring crack!! "
            target.fighter.hp -= self.damage
            self.consume()
        else:
            raise exceptions.Impossible("No enemy is close enough to strike.")

        if target.fighter.is_dead():
            return DieAction(entity=target, cause=consumer)
예제 #7
0
    def perform(self):
        """Performs the attack - first we validate if the attack is valid, then we start running through
        all the attacks that compose the full attack. For each attack we:
            * roll a hit die
            * compare it to the 'target number'
            * If the roll is less than the target, that attack will hit.
            * We then calculate the damage and generate an appropriate message.
            * For each additional hit, there is a -1 tohit penalty.
        """
        target = self.target_actor
        if not target:
            raise exceptions.Impossible("Nothing to attack!")
        elif target == self.entity:
            if self.entity.is_player():
                raise exceptions.Impossible("You cannot attack yourself!")

            raise exceptions.Impossible(f"The {target} wobbles in place.")

        results = []

        # Iterate through all the attacks
        for atk in self.offense.attacks:
            if self.roll_hit_die() < self.calc_target_number(target):
                dmg = self.execute_damage(target, atk)

                # Generate appropriate message
                if dmg > 0:
                    self.hit_msg(target, atk, dmg)
                else:
                    # Blocking message
                    self.blocked_msg(target)

                # A hit was executed - check for any passive reactions
                if target.has_comp("passive"):
                    # Hopefully we can just reverse the dx and dy to target the attacker.
                    results.append(
                        PassiveAttack(entity=target,
                                      dx=self.dx * -1,
                                      dy=self.dy * -1))
            else:
                self.miss(target)

        # Check if the target is dead...
        if target.fighter.is_dead():
            results.append(DieAction(entity=target, cause=self.entity))

        return results
예제 #8
0
    def activate(self, action):
        """If the selected actor is valid, confuses that actor and consumes this consumable."""
        consumer = action.entity
        # Get the actor at the location
        target = action.target_actor

        if not self.engine.game_map.visible[action.target_xy]:
            raise exceptions.Impossible(
                "You cannot target an area that you cannot see.")
        if not target:
            raise exceptions.Impossible("You must select an enemy to target.")
        if target is consumer:
            raise exceptions.Impossible("You cannot confuse yourself!")

        action.msg = f"The eyes of the {target.name} look vacant, as it starts to stumble around!"

        target.states.add_state("confused", self.number_of_turns)
        self.consume()
예제 #9
0
    def activate(self, action):
        """Heals the consumer and consumes the entity holding this consumable."""
        consumer = action.entity
        healing_amount = self.amount + random.randint(1, self.amount)
        amount_recovered = consumer.fighter.heal(healing_amount)

        if amount_recovered > 0:
            action.msg = f"You consume the {self.parent.name}, and recover {amount_recovered} HP!"
            self.consume()
        else:
            raise exceptions.Impossible(f"Your health is already full.")
예제 #10
0
    def perform(self):
        """Attempts to moves the entity a destination coordinate. We conduct a thorough set of checks to
        make sure the move is valid, and then move the entity. If the entity walks into a trap, we return a
        TrapAction for that trap.
        """
        if "trapped" in self.entity.states.states:
            # return WriggleAction(self.entity, self.dx, self.dy)
            raise exceptions.Impossible("Actor is trapped and cannot move!")

        dest_x, dest_y = self.dest_xy

        if not self.entity.gamemap.in_bounds(dest_x, dest_y):
            # Destination is out of bounds.
            raise exceptions.Impossible("That way is out of bounds!")

        if not self.entity.gamemap.walkable(dest_x, dest_y):
            # Destination is blocked by a tile.
            if self.entity.is_player():
                raise exceptions.Impossible("That way is not walkable!")

            # No msg for other monsters
            return

        # Theoretically, this won’t ever trigger, it's a safeguard.
        if self.blocking_entity:
            # Destination is blocked by an entity.
            if self.entity.is_player:
                raise exceptions.Impossible("That way is blocked.")

            # No msg for other monsters
            return

        self.entity.move(self.dx, self.dy)

        # Did we trigger a trap?
        trap = self.entity.gamemap.get_trap_at(dest_x, dest_y)
        if trap:
            # Trigger it
            return TrapAction(self.entity, trap)
예제 #11
0
파일: equipment.py 프로젝트: elunna/labhack
    def toggle_equip(self, item):
        """ Attempts to equip an unequipped item, or unequip an equipped item.
            Returns a string describing what happened.
        """
        # Can we equip it?
        if not getattr(item, "equippable", None):
            raise exceptions.Impossible("f{item.name} is not an Equippable!")

        # Does the item slot match what is available?
        slot = item.equippable.equipment_type.name

        if self.slots[slot] == item:
            return self.unequip_from_slot(slot)
        else:
            return self.equip_to_slot(slot, item)
예제 #12
0
    def perform(self):
        """ Take the stairs, if any exist at the entity's location. """
        player_location = (self.entity.x, self.entity.y)
        stair_location = self.dungeon.current_map.downstairs_location

        if player_location == stair_location:
            new_level_generated = False

            # Do we have a level below us yet?
            if self.dungeon.dlevel == len(self.dungeon.map_list):
                # Generate a new level and add it to the map_list
                self.dungeon.generate_floor()
                new_level_generated = True

            self.dungeon.move_downstairs(self.entity)

            if new_level_generated:
                # This solves the annoying problem of the player appearing on top of other monsters.
                # We have to populate after placing the player.
                self.dungeon.populate_map(self.dungeon.dlevel)

            self.msg = "You descend the stairs."
        else:
            raise exceptions.Impossible("There are no stairs here.")
예제 #13
0
def test_Impossible__is_Exception():
    i = exceptions.Impossible()
    assert isinstance(i, Exception)