Beispiel #1
0
    def wandering(self):
        """
        Calculate the action of a monster without a specific goal in mind.
        """

        if self.currentLevel.player in self.fov:
            self.state = ais.FIGHTING
            return self.fighting()

        assert self.direction is not None

        ordered_moves = coordinates.adjacent_coords_sorted(
            self.coords, self.direction)
        possible_moves = [
            x for x in ordered_moves if self.currentLevel.canMove(self, x)
        ]
        if len(possible_moves) == 0:
            # You're stuck!  Give up, just rest there.
            self.state = ais.RESTING
            return self.resting()
        else:
            move_coords = possible_moves[0]
            self.direction = coordinates.subtract(move_coords, self.coords)
            return action.Move(self,
                               coordinates.subtract(move_coords, self.coords))

        assert False
Beispiel #2
0
    def closeToPlayer(self):
        """
        Pathfind to the player, and attack him if possible.
        """

        player_location = self.currentLevel.player.coords

        # If adjacent to the player, attack him.
        if coordinates.adjacent(player_location, self.coords):
            if rng.percentChance(self.specfreq):
                return action.SpecialMelee(self, self.currentLevel.player,
                                           self.spec)
            else:
                return action.Attack(
                    self, self.currentLevel.player,
                    "%(SOURCE_NAME)s attacks %(TARGET_NAME)s! (%(DAMAGE)d)")

# Otherwise, pathfind toward him.
        else:
            path = pf.find_shortest_path(self.currentLevel, self.coords,
                                         player_location, False)
            if path != []:
                move_coords = coordinates.subtract(path[1], path[0])
                return action.Move(self, move_coords)
            else:
                return action.Wait(self)
Beispiel #3
0
    def traveling(self):
        """
        Calculate the action of a monster moving to a specific location.

        Note that a "path" variable must exist for this to make sense.
        """

# self.path[0] should be the monster's current square.
# self.path[1] should be the square the monster wants to move to.
# self.path[-1] should be the monster's ultimate destination.

        assert self.path != None, "Despite the monster being in state TRAVELING, the path variable is null."

        if self.currentLevel.player in self.fov:
            self.state = ais.FIGHTING
            return self.fighting()
        else:
            path_is_invalid = False

            if len(self.path) == 0:
                assert False # This shouldn't happen!
                path_is_invalid = True
            elif self.coords != self.path[0]:
# Something has moved the monster since its last turn.
                path_is_invalid = True
            elif len(self.path) == 1:
# Since self.coords == self.path[0], the monster has reached its destination!
                self.state = ais.WANDERING
                return self.wandering()
            elif not self.canMove(self.path[1]):
                path_is_invalid = True

            if path_is_invalid:
                if len(self.path) == 0:
# If the path is completely empty, something has gone wrong.
                    assert False
# Just give up and return to being stationary.
                    self.state = ais.RESTING
                    return self.resting()
                else:
                    destination = self.path[-1]
                    self.path = pf.find_shortest_path(self.currentLevel, self.coords, destination, True)
                    if len(self.path) == 0:
# There simply is no path to the destination!
# Set self.path to only contain the destination, so that next turn, this code
# attempts to find another path.
                        self.path = [destination]
                        return action.Wait(self)
                    elif len(self.path) == 1:
# This should not happen!
                        assert False
                        return action.Wait(self)

            if self.canMove(self.path[1]):
                move_direction = coordinates.subtract(self.path[1], self.coords)
                self.path.pop(0)
                return action.Move(self, move_direction)
            else:
                assert False, "The supposedly legal path contains an illegal move!"
                return action.Wait(self)
Beispiel #4
0
    def fighting(self):
        """
        Calculate the action of a monster who sees the player.
        """

        if self.currentLevel.player not in self.fov:
            if self.player_last_location is not None:
                # The player has escaped!  Find a likely square where he could have gone.
                adjacent_coords = coordinates.adjacent_coords(
                    self.player_last_location)
                legal_coords = [
                    i for i in adjacent_coords
                    if coordinates.legal(i, self.currentLevel.dimensions)
                ]
                passable_coords = [
                    i for i in legal_coords if self.currentLevel.isEmpty(i)
                ]
                out_of_vision_coords = \
                    [i for i in passable_coords if i not in self.fov]

                if len(out_of_vision_coords) > 0:
                    # There is a possible escape route!  Pursue!
                    self.direction = coordinates.subtract(
                        rng.choice(out_of_vision_coords),
                        self.player_last_location)
                    self.path = pf.find_shortest_path(
                        self.currentLevel, self.coords,
                        self.player_last_location, False)
                    if self.path == []:
                        # There is no route to the player's escape route.  Wait, but stay in
                        # state FIGHTING so as to take advantage of any route that opens up.
                        return action.Wait(self)
                    self.state = ais.TRAVELING
                    return self.traveling()
                else:
                    # There is no possible escape route; give up and rest.
                    self.state = ais.RESTING
                    return self.resting()

            else:
                assert False

        else:
            self.player_last_location = self.currentLevel.player.coords

            if self.AICode == "CLOSE":
                return self.closeToPlayer()

            elif self.AICode == "RANGEDAPPROACH":
                return self.rangedApproach()

            else:
                raise exc.InvalidDataWarning(
                    "The monster %s has an unknown AICode, %s" % (self.name,
                                                                  self.AICode))
                return action.Wait(self)

        assert False
Beispiel #5
0
def do_special_melee(attack_type, source, target):
    """
    Have a Dude perform a special melee attack.

    attack_type - a string representing the type of special attack.
    source - the Dude attacking.
    target - the Dude being attacked.
    """

    if attack_type == "CRITICAL":
        damage_dealt = CRIT_MULTIPLIER * \
                       damage(source.attack, target.defense,
                              source.char_level, target.char_level)
        source.currentLevel.messages.append(
        "%(SOURCE_NAME)s runs %(TARGET_NAME)s all the way through! (%(DAMAGE)d)"
            % {"SOURCE_NAME": source.getName(),
               "DAMAGE": damage_dealt,
               "TARGET_NAME": target.getName()})
        target.cur_HP -= damage_dealt
        target.checkDeath()
    elif attack_type == "KNOCK":
        damage_dealt = KNOCK_DAMAGE
        direction = coordinates.subtract(target.coords, source.coords)
        source.currentLevel.messages.append(
        "%(SOURCE_NAME)s delivers a wicked punch to %(TARGET_NAME)s! (%(DAMAGE)d)"
            % {"SOURCE_NAME": source.getName(),
               "DAMAGE": damage_dealt,
               "TARGET_NAME": target.getName()})
        for i in range(KNOCK_DISTANCE):
            display.refresh_screen()
            destination = coordinates.add(target.coords, direction)
            if target.canMove(destination):
                target.currentLevel.moveDude(target, destination)
            else:
                break
        display.refresh_screen()
        target.cur_HP -= damage_dealt
        target.checkDeath()
    elif attack_type == "EXPLODE":
        explode_action = Explode(source.currentLevel, source.coords, 10)
        source.currentLevel.messages.append(
        "%(SOURCE_NAME)s explodes!"
            % {"SOURCE_NAME": source.getName()})
        explode_action.do()
    elif attack_type == "STICK":
        damage_dealt = damage(source.attack, target.defense,
                       source.char_level, target.char_level) / 5
        source.currentLevel.messages.append(
        "%(SOURCE_NAME)s spins a web around %(TARGET_NAME)s! (%(DAMAGE)d)"
            % {"SOURCE_NAME": source.getName(),
               "DAMAGE": damage_dealt,
               "TARGET_NAME": target.getName()})
        target.giveCondition(cond.Stuck(8))
        target.cur_HP -= damage_dealt
        target.checkDeath()
    else:
        raise exc.InvalidDataWarning("%s special ability used by %s on %s."
                                     % (attack_type, str(source), str(target)))
Beispiel #6
0
    def do(self):
        cur_lev = self.source.currentLevel
        next_loc = self.source.coords

# Essentially a for loop, for i in range(self.distance).
        i = 0
        while True:
            if i >= self.distance:
                cur_lev.messages.append("%s pounced, but caught only air."
                    % self.source.getName())
                break

            i += 1

            next_loc = coordinates.add(self.source.coords, self.direction)
            display.refresh_screen()
            
            if not cur_lev.isEmpty(next_loc):
                cur_lev.messages.append("%s pounced at the wall."
                    % self.source.getName())
                break
            elif next_loc in cur_lev.dudeLayer:
                # The pouncer hit a dude.
                target = cur_lev.dudeLayer[next_loc]
                # Bounce off: behind the dude if possible, in front otherwise.
                behind = coordinates.add(next_loc, self.direction)
                in_front = coordinates.subtract(next_loc, self.direction)

                if (cur_lev.isEmpty(behind) and behind not in cur_lev.dudeLayer):
                    cur_lev.moveDude(self.source, behind)
# The pouncer should already be in front of the target, so if it is not going
# through them, no motion is necessary.

                damage_dealt = damage(self.source.attack, target.defense,
                               self.source.char_level, target.char_level)
                cur_lev.messages.append("%s pounced on %s! (%d)"
                    % (self.source.getName(), target.getName(), damage_dealt))
                target.cur_HP -= damage_dealt
                target.checkDeath()
                break

            else:
                cur_lev.moveDude(self.source, next_loc)

        display.refresh_screen()
        return self.source.speed