Example #1
0
    def probableRangedAttack(self):
        """
        Return an action for a ranged attack on a target if such an attack is
        possible.  Otherwise, return None.
        """
        if "two_square_thrower" in self.tags:
            if self.currentLevel.player in self.fov \
                and coordinates.minimumPath(self.coords, self.currentLevel.player.coords) in range(1, 4):
                
                possible_directions = ((2,0),(2,2),(0,2),(-2,2),(-2,0),(-2,-2),(0,-2),(2,-2))
                possible_targets = [coordinates.add(self.coords, i) for i in possible_directions if self.currentLevel.isEmpty(coordinates.add(self.coords, i))]
                visible_targets = [coords for coords in possible_targets if coords in self.fov]
                close_targets = [coords for coords in visible_targets if (coordinates.minimumPath(coords, self.currentLevel.player.coords) <= 1)]
                actual_targets = [coords for coords in close_targets if coords not in self.currentLevel.dudeLayer]
                if len(actual_targets) == 0:
                    return None
                final_target = rng.choice(actual_targets)
                return action.ThrowGrenade(self, final_target)
            else:
                return None
        elif "twelve_square_firer" in self.tags:
            direction = coordinates.get_cardinal_direction(self.coords,
                          self.currentLevel.player.coords)
            dist = coordinates.minimumPath(self.coords,
                   self.currentLevel.player.coords)
            if self.currentLevel.player in self.fov \
                and direction is not None \
                and dist < 12:

                return action.FireArrow(self, direction, 12)
            else:
                return None
        else:
            return None
Example #2
0
File: dude.py Project: nrook/Spirit
    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
Example #3
0
File: dude.py Project: nrook/Spirit
    def statue(self):
        """
        The statue AI pattern is as follows:

        If a monster that meets certain conditions is in view, do
        a general haste.
        If no such monster is in view, teleport adjacent to a damaged monster.
        If no such monster exists, then teleport randomly.
        """

        for d in self.fov.dudes:
            if self.spec == "QUICKEN":
                if (not d.isPlayer()) and (d.AICode != "STATUE"):
                    return action.HasteAll(self, 8, False, False)
            else:
                assert False

# If the statue is stuck, it can't teleport, so it just stays.
        if self.hasCondition("STUCK"):
            return action.Wait(self)

# If the statue did not do anything to monsters in view, it must teleport.
        for m in self.currentLevel.dudeLayer:
            if m.cur_HP < m.max_HP and not m.isPlayer() and (m.AICode !=
                                                             "STATUE"):
                # Aha, a target!
                destination_candidates = coordinates.adjacent_coords(m.coords)
                destination_options = [
                    i for i in destination_candidates
                    if self.currentLevel.isEmpty(i)
                    and i not in self.currentLevel.dudeLayer
                ]
                if destination_options != []:
                    return action.Teleport(self,
                                           rng.choice(destination_options))


# If there are no monsters to which the statue can teleport, teleport randomly.
        for i in range(100):
            destination = rng.randomPointInRect(
                (0, 0), (self.currentLevel.dimensions[0] - 1,
                         self.currentLevel.dimensions[1] - 1))
            if self.currentLevel.isEmpty(destination) and \
                destination not in self.currentLevel.dudeLayer:

                return action.Teleport(self, destination)

        return action.Wait(self)
Example #4
0
File: dude.py Project: nrook/Spirit
    def getConditionAction(self):
        """
        Get an action governed by the Dude's condition, not its decisions.

        Return an action if the Dude's conditions are making it take an action.
        Return "None" if they are not.
        """
        possible_actions = []
        for condition in self.conditions.values():
            new_action = condition.getAction(self)
            if new_action is not None:
                possible_actions.append(new_action)

        if len(possible_actions) > 0:
            return rng.choice(possible_actions)
        else:
            return None
Example #5
0
def randomDungeon():
    """
    Gets a random dungeon, using a very simple room/corridor model.
    
    The room/corridor model used is similar to that of Rogue; the map is
    divided into nine sectors, each of which is randomly called a room,
    a corridor, or empty.  Once this is done, rooms and corridors are connected
    to adjacent rooms and corridors.
    
    This is coded terribly because it will be replaced someday.
    """
    
    map_dimensions = (60, 60)
    map_nwcorner = (10, 10)
    sector_size = (12, 12)
    sector_nwcorners = {}
    for x in range(0, 3):
        for y in range(0, 3):
            sector_nwcorners[(x, y)] = (
                map_nwcorner[0] + sector_size[0] * x,
                map_nwcorner[1] + sector_size[1] * y
                )
                
    sector_types = {}
    for x in range(0, 3):
        for y in range(0, 3):
            percent = rng.randInt(1, 100)
            if percent <= 60:
                sector_types[(x, y)] = 1 # it's a room!
            elif percent <= 75:
                sector_types[(x, y)] = 2 # it's a corridor!
            else:
                sector_types[(x, y)] = 0 # it's empty!
    
    room_nwcoords = {}
    room_secoords = {}
    
    for sector_coords in sector_types.keys():
        if sector_types[sector_coords] == 1:
            room_created = False
            sector_nw = sector_nwcorners[sector_coords]
            sector_se = (sector_nw[0] + sector_size[0] - 1, sector_nw[1] + sector_size[1] - 1)
            while not room_created:
                room_nw = (rng.randInt(sector_nw[0], sector_se[0]),
                           rng.randInt(sector_nw[1], sector_se[1]))
                room_se = (room_nw[0] + rng.randInt(3, 8),
                           room_nw[1] + rng.randInt(3, 8))
            
                # check validity of room dimensions
                if room_se[0] <= sector_se[0] and room_se[1] <= sector_se[1]:
                    room_nwcoords[sector_coords] = room_nw
                    room_secoords[sector_coords] = room_se
                    room_created = True
                    
        elif sector_types[sector_coords] == 2:
            # A corridor is currently implemented as just a 1-space room.
            corridor_coords = (rng.randInt(sector_nwcorners[sector_coords][0],
                                           sector_nwcorners[sector_coords][0] + sector_size[0] - 1,),
                               rng.randInt(sector_nwcorners[sector_coords][1],
                                           sector_nwcorners[sector_coords][1] + sector_size[1] - 1,))
            room_nwcoords[sector_coords] = corridor_coords
            room_secoords[sector_coords] = corridor_coords
    
    # Check whether everywhere is accessible; if not, do a redo.
    sector_is_accessible = {}
    for x in range(3):
        for y in range(3):
            sector_is_accessible[(x, y)] = False
    
    for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)):
        if True not in sector_is_accessible.values() and sector_types[coord] != 0:
            sector_is_accessible[coord] = True
        
        if sector_is_accessible[coord] == True and sector_types[coord] != 0:
            for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)):
                adjacent_coord = coordinates.add(coord, coord_adjustment)
                if (adjacent_coord[0] >= 0 and
                    adjacent_coord[0] < 3 and
                    adjacent_coord[1] >= 0 and
                    adjacent_coord[1] < 3):
                    
                    sector_is_accessible[adjacent_coord] = True
    
    for accessible in sector_is_accessible.items():
        if sector_types[accessible[0]] != 0 and not accessible[1]:
            # Oops.  Give up and try again.
            return randomDungeon()
    
    entrance_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1])
    exit_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1])
    entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], room_secoords[entrance_sector])
    exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], room_secoords[exit_sector])
    
    ret_dungeon = level.empty_dungeon(map_dimensions)
    
    for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)):
        if sector_types[coord] != 0:
            for x in range(room_nwcoords[coord][0], room_secoords[coord][0] + 1):
                for y in range(room_nwcoords[coord][1], room_secoords[coord][1] + 1):
                    if sector_types[coord] == 1:
                        ret_dungeon[(x, y)] = level.ROOM_INTERIOR_GLYPH
                    else:
                        ret_dungeon[(x, y)] = level.CORRIDOR_GLYPH
            
            for coord_adjustment in ((1, 0), (0, 1)):
                adjacent_coord = coordinates.add(coord, coord_adjustment)
                if (adjacent_coord[0] < 3 and adjacent_coord[1] < 3 and sector_types[adjacent_coord] != 0):
                    make_corridor(ret_dungeon,
                        rng.randomPointInRect(room_nwcoords[coord], room_secoords[coord]),
                        rng.randomPointInRect(room_nwcoords[adjacent_coord], room_secoords[adjacent_coord]))
    
    ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH
    ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH
    
    return ret_dungeon
Example #6
0
def randomDungeon():
    """
    Gets a random dungeon, using a very simple room/corridor model.
    
    The room/corridor model used is similar to that of Rogue; the map is
    divided into nine sectors, each of which is randomly called a room,
    a corridor, or empty.  Once this is done, rooms and corridors are connected
    to adjacent rooms and corridors.
    
    This is coded terribly because it will be replaced someday.
    """
    
    map_dimensions = (MAX_SIZE_X, MAX_SIZE_Y)
    map_nwcorner = (NW_CORNER_X, NW_CORNER_Y)
    sector_size = (SECTOR_SIZE_X, SECTOR_SIZE_Y)
    sector_list = [(x, y) for x in range(NUM_SECTORS_X) 
                          for y in range(NUM_SECTORS_Y)]
    sector_nwcorners = {}
    for x in range(NUM_SECTORS_X):
        for y in range(NUM_SECTORS_Y):
            sector_nwcorners[(x, y)] = (
                map_nwcorner[0] + sector_size[0] * x,
                map_nwcorner[1] + sector_size[1] * y
                )
                
    sector_types = {}
    for x in range(NUM_SECTORS_X):
        for y in range(NUM_SECTORS_Y):
            percent = rng.randInt(1, 100)
            if percent <= 25:
                sector_types[(x, y)] = st.ROOM
            elif percent <= 60:
                sector_types[(x, y)] = st.DOUBLE_ROOM
            elif percent <= 75:
                sector_types[(x, y)] = st.CORRIDOR
            else:
                sector_types[(x, y)] = st.EMPTY
    
    room_nwcoords = {}
    room_secoords = {}
    
    for sector_coords in sector_types.keys():
        sector_nw = sector_nwcorners[sector_coords]
        sector_se = (sector_nw[0] + sector_size[0] - 1,
                     sector_nw[1] + sector_size[1] - 1)

        if sector_types[sector_coords] in (st.ROOM, st.DOUBLE_ROOM):
            (room_nwcoords[sector_coords], room_secoords[sector_coords]) \
                = choose_room_corners(sector_nw, sector_se)
                    
        elif sector_types[sector_coords] == st.CORRIDOR:
            # A corridor is currently implemented as just a 1-space room.
            corridor_coords = (rng.randInt(sector_nw[0], sector_se[0]),
                rng.randInt(sector_nw[1], sector_se[1]))

            room_nwcoords[sector_coords] = corridor_coords
            room_secoords[sector_coords] = corridor_coords
    
    # Check whether everywhere is accessible; if not, do a redo.
    sector_is_accessible = {}
    for x in range(NUM_SECTORS_X):
        for y in range(NUM_SECTORS_Y):
            sector_is_accessible[(x, y)] = False
    
    for coord in sector_list:

        if True not in sector_is_accessible.values() \
            and sector_types[coord] != 0:

            sector_is_accessible[coord] = True
        
        if sector_is_accessible[coord] == True \
            and sector_types[coord] != st.EMPTY:

            for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)):
                adjacent_coord = coordinates.add(coord, coord_adjustment)
                if (adjacent_coord[0] >= 0 and
                    adjacent_coord[0] < NUM_SECTORS_X and
                    adjacent_coord[1] >= 0 and
                    adjacent_coord[1] < NUM_SECTORS_Y):
                    
                    sector_is_accessible[adjacent_coord] = True
    
    for accessible in sector_is_accessible.items():
        if sector_types[accessible[0]] != 0 and not accessible[1]:
            # Oops.  Give up and try again.
            return randomDungeon()
    
    entrance_sector = rng.choice([coords for coords in sector_types.keys() 
                                 if sector_types[coords] in 
                                 (st.ROOM, st.DOUBLE_ROOM)])
    exit_sector = rng.choice([coords for coords in sector_types.keys() 
                              if sector_types[coords] in
                              (st.ROOM, st.DOUBLE_ROOM)])
    entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], 
                                            room_secoords[entrance_sector])
    exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], 
                                        room_secoords[exit_sector])
    
    ret_dungeon = level.empty_dungeon(map_dimensions)
    
    for coord in sector_list:
        if sector_types[coord] != st.EMPTY:
            if sector_types[coord] == st.CORRIDOR:
                fill_glyph = level.CORRIDOR_GLYPH
            else:
                fill_glyph = level.ROOM_INTERIOR_GLYPH

            arrays.fill_rect(ret_dungeon, room_nwcoords[coord], 
                room_secoords[coord], fill_glyph)
            
# If there is another room to the south or east, make a corridor from this room
# to it.
            for coord_adjustment in ((1, 0), (0, 1)):
                adjacent_coord = coordinates.add(coord, coord_adjustment)
                if (adjacent_coord[0] < NUM_SECTORS_X 
                    and adjacent_coord[1] < NUM_SECTORS_Y
                    and sector_types[adjacent_coord] != 0):

                    make_corridor(ret_dungeon,
                        rng.randomPointInRect(room_nwcoords[coord], 
                                              room_secoords[coord]),
                        rng.randomPointInRect(room_nwcoords[adjacent_coord], 
                                              room_secoords[adjacent_coord]))

# If the room type is DOUBLE_ROOM, bolt on a second room to the first.
# This room can overflow! That is intentional.
            if sector_types[coord] == st.DOUBLE_ROOM:
                max_second_se = (room_secoords[coord][0] + MIN_ROOM_SIZE,
                                 room_secoords[coord][1] + MIN_ROOM_SIZE)
                (second_nw, second_se) = choose_room_corners(
                    room_nwcoords[coord], max_second_se)

                arrays.fill_rect(ret_dungeon, second_nw, second_se, 
                    level.ROOM_INTERIOR_GLYPH)
    
    ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH
    ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH
    
    return ret_dungeon
Example #7
0
    def get(self,atktype,location):
           
        # ---- Get location. ---------------------------- #
        
        # Read damage type.
        self.atktype = atktype
        
        # Determine location.
        if location == 'random': self.location = (hit[self.roll()],)
        else: self.location = (location,)
        
        # Set multiplier.
        if atktype in mult: self.multiplier = mult[atktype]
        
        # ---- Handle thresholds and sublocations.  ---- #
        
        loc = self.location[0]
        rl = self.die.roll()         
        
        # Low Tech Hit
        if loc in ['Arm', 'Leg']:
            r2 = self.die.roll()
            # Arm
            if 'Arm' in loc:
                if r2 <= 3: self.location = (loc, 'Forearm')
                elif r2 == 4: self.location = (loc, 'Elbow')
                elif r2 == 5: self.location = (loc, 'Upper Arm') 
                elif r2 == 6: self.location = (loc, 'Shoulder')   
            # Leg
            if 'Leg' in loc:
                if r2 <= 3: self.location = (loc, 'Shin')
                elif r2 == 4: self.location = (loc, 'Knee')
                elif r2 > 4: self.location = (loc, 'Thigh')
        elif loc in ['Shin', 'Knee', 'Thigh']:
            self.location = ('Leg', loc)
            loc = 'Leg'
        elif loc in ['Forearm', 'Elbow', 'Upper Arm', 'Shoulder']:
            self.location = ('Arm', loc)    
            loc = 'Arm' 
        
        if (rl == 1): # Roll of 1.
            
            # Arm or leg.
            if not 'Vascular' in loc and ('Arm' in loc or 'Leg' in loc
                ) and not ('cr' in atktype): # Vascular Hit
                # Get Side
                side = loc.split()[0]
                chunk = 'Arm' if ('Arm' in loc) else 'Leg'
                
                # Reformat locs
                if len(loc.split()) == 1 or chunk in self.location[-1]:
                    self.location = (self.location[-1], '%s Vascular' % (chunk))
                else:
                    self.location = (side + ' ' + self.location[-1], 
                        '%s Vascular' % (chunk))
                    
            # In the face.
            elif 'Face' in loc:
                self.location = (loc, 'Skull' if (atktype in 
                    ['imp','burn'] or 'pi' in atktype) else 'Nose')
                    
            # Hand or feet.
            elif atktype in ['cr','cut','burn'] or 'pi' in atktype and (
                'Hand' in loc or 'Foot' in loc):
                self.location = (choice(['Left','Right']) + ' ' + loc, 
                    'Wrist' if ('Hand' in loc) else 'Ankle')
                    
            # Neck or torso.
            elif atktype in ['cut','imp','burn'] or 'pi' in atktype and (
                'Neck' in loc or 'Torso' in loc):
                self.location = (loc, 
                    'Neck Vascular' if ('Neck' in loc) else 'Vitals')
                        
        # Abdomen
        if 'Abdomen' == loc:
            if rl == 1: self.location = (loc, 'Vitals')
            elif rl <= 4: self.location = (loc, 'Digestive Tract')
            elif rl == 5: self.location = (loc, 'Pelvis')
            else: self.location = (loc, 'Groin')
                
        # Face sub-location (when not already resolved).
        if self.facesub and 'Face' == loc and len(self.location) == 1:
            r1 = self.die.roll()
            if r1 == 1: self.location = (loc, 'Jaw')
            elif r1 == 2: self.location = (loc, 'Nose')
            elif r1 == 3: self.location = (loc, 'Ear')
            elif r1 == 4 or r1 == 5: self.location = (loc, 'Cheek')           
            else: self.location = (loc, 'Eye')        
         
        # Set threshold dictionary; order.
        self.SetThreshold()

        # ---- Process notes, wounds. -------------------- #
        
        notetable.NoteProcessor(self)
        woundtable.WoundProcessor(self)
        
        # ---- Process critical hits. -------------------- #
        
        if loc in ['Face', 'Skull', 'Eye', 'Ear', 'Nose', 'Cheek', 'Jaw']:
            self.CriticalHead()
        else: self.CriticalHit()        
        
        # ---- Save data to datastore. ----------------- #
        
        self.SaveStats(atktype,location)