示例#1
0
 def _search_for_path(self, border_func, end_func, max_steps):
     paths = [None] * 4
     paths[0] = self._check_steps(Position(-1, 0), border_func, end_func,
                                  max_steps)
     paths[1] = self._check_steps(Position(0, -1), border_func, end_func,
                                  max_steps)
     paths[2] = self._check_steps(Position(1, 0), border_func, end_func,
                                  max_steps)
     paths[3] = self._check_steps(Position(0, 1), border_func, end_func,
                                  max_steps)
     cands = [x for x in paths if x is not None]
     if not cands:
         return None
     elif len(cands) == 1:
         return cands[0][1:]
     # take the end point closest to our target
     final_path = cands[0]
     min_dist = final_path[-1].dist(self.target)
     for this_path in cands[1:]:
         dist = this_path[-1].dist(self.target)
         if dist < min_dist:
             min_dist = dist
             final_path = this_path
         elif dist == min_dist and random.randint(0, 1) == 0:
             final_path = this_path
     return final_path[1:]  # path's include self.pos
示例#2
0
 def _find_best_path_step(self):
     """Find the cheapest path to final_pos, and return the next step
        along the path."""
     if self.path:
         next_step = self.path.pop(0)
         if next_step.dist(self.pos) < 2:
             return next_step
         else:
             # Been bounced off the path
             self.path = []
     new_pos = None
     if self.target.z < self.pos.z:
         # We need to try heading down.
         new_pos = Position(self.pos.x, self.pos.y, self.pos.z - 1)
     if self.target.x == self.pos.x and self.target.y == self.pos.y and \
             self.target.z > self.pos.z:
         # We try heading up
         new_pos = Position(self.pos.x, self.pos.y, self.pos.z + 1)
     if new_pos:
         if new_pos in self._last_steps:
             # ladder, so we allow backtracking
             self._last_steps.remove(new_pos)
         return new_pos
     cur_dist = self.target.dist(self.pos)
     if cur_dist < 2:
         # We're right ontop of our target, so just go there
         return self.target
     # Find the cheapest spot close to us that moves us closer to the target
     best, min_cost = self._find_min_cost_neighbour(self.target)
     if min_cost < 20 or not self.gameboard.in_bounds(self.pos) \
             or not self.gameboard.in_bounds(best):
         # If we're not on the gameboard yet, there's no point in looking
         # for an optimal path.
         return best
     # Else expensive step, so think further
     if self._is_fence(best):
         path = self._find_fence_gap()
     elif min_cost == 30:
         # building
         path = self._find_nearest_corner()
     else:
         # We're looping
         self._last_steps = []
         return self.pos
     if path:
         self.path = path[1:]  # exclude 1st step
         return path[0]
     return best
示例#3
0
 def _calc_next_move(self):
     """Find the path to the target"""
     if self.hunting:
         # Check if we need to update our idea of a target
         if self.closest and self.closest in self.gameboard.chickens:
             stealth = self.closest.get_stealth()
             roll = random.randint(1, 100)
             is_visible = roll > stealth
             if not is_visible:
                 self._select_prey()
             elif not self.target:
                 self.target = self.closest.pos
         else:
             # Either no target, or someone ate it
             self._select_prey()
     if not self.target:
         self.target = self.start_pos
         self._last_steps = []
     if self.target == self.pos:
         # No need to move, but we will need to update the target
         self.target = None
         return self.pos
     if self.target.to_tile_tuple() == self.pos.to_tile_tuple():
         # Only differ in z, so next step is in z
         if self.target.z < self.pos.z:
             new_z = self.pos.z - 1
         else:
             new_z = self.pos.z + 1
         return Position(self.pos.x, self.pos.y, new_z)
     return self._find_best_path_step()
示例#4
0
 def __init__(self, tile_pos, gameboard):
     # load images
     self._image_left = imagecache.load_image(self.IMAGE_FILE)
     self._image_right = imagecache.load_image(self.IMAGE_FILE,
                                               ("right_facing", ))
     # Create the animal somewhere far off screen
     Sprite.__init__(self, self._image_left, (-1000, -1000))
     self.image_left = self._image_left.copy()
     self.image_right = self._image_right.copy()
     if hasattr(tile_pos, 'to_tile_tuple'):
         self.pos = tile_pos
     else:
         self.pos = Position(tile_pos[0], tile_pos[1], 0)
     self.equipment = []
     self.accoutrements = []
     self.abode = None
     self.facing = 'left'
     self.gameboard = gameboard
示例#5
0
 def move(self):
     """A free chicken will wander around aimlessly"""
     pos_x, pos_y = self.pos.to_tile_tuple()
     surrounds = [
         Position(pos_x + dx, pos_y + dy) for dx in [-1, 0, 1]
         for dy in [-1, 0, 1]
     ]
     pos_options = [
         pos for pos in surrounds if self.gameboard.in_bounds(pos) and self.
         gameboard.tv.get(pos.to_tile_tuple()) == self.gameboard.GRASSLAND
         and not self.gameboard.get_outside_chicken(pos.to_tile_tuple())
     ] + [self.pos]
     self.pos = pos_options[random.randint(0, len(pos_options) - 1)]
示例#6
0
 def chop(self):
     if self.has_axe():
         pos_x, pos_y = self.pos.to_tile_tuple()
         surrounds = [
             Position(pos_x + dx, pos_y + dy) for dx in [-1, 0, 1]
             for dy in [-1, 0, 1]
         ]
         tree_options = [
             pos for pos in surrounds if self.gameboard.in_bounds(pos)
             and self.gameboard.is_woodland_tile(pos)
         ]
         if tree_options:
             num_trees_to_cut = random.randint(1, len(tree_options))
             trees_to_cut = random.sample(tree_options, num_trees_to_cut)
             for tree_pos in trees_to_cut:
                 self.gameboard.add_wood(5)
                 self.gameboard.tv.set(tree_pos.to_tile_tuple(),
                                       self.gameboard.GRASSLAND)
示例#7
0
 def _update_pos(self, new_pos):
     """Update the position, making sure we don't step on other foxes"""
     if not self.hunting and not self.gameboard.in_bounds(self.pos):
         self.safe = True
         return self.pos
     if new_pos == self.pos:
         # We're not moving, so we can skip all the checks
         return new_pos
     blocked = self.gameboard.get_animal_at_pos(new_pos, 'fox') is not None
     final_pos = new_pos
     if blocked:
         if new_pos.z != self.pos.z or self.pos.z != 0:
             # We can only move up and down a ladder
             moves = [
                 Position(self.pos.x, self.pos.y, z)
                 for z in range(self.pos.z - 1, self.pos.z + 2) if z >= 0
             ]
         else:
             moves = [self.pos + step for step in NEIGHBOUR_8]
         # find the cheapest point in moves that's not blocked
         final_pos = None
         min_cost = 1000
         for poss in moves:
             if self.gameboard.get_animal_at_pos(poss, 'fox'):
                 continue  # blocked
             cost = self._cost_tile(poss)
             if cost < min_cost:
                 min_cost = cost
                 final_pos = poss
             if cost == min_cost and random.randint(0, 1) > 0:
                 # Add some randomness in this case
                 final_pos = poss
     if not final_pos:
         # No good choice, so stay put
         return self.pos
     if self._is_fence(final_pos) and not self.dig_pos:
         return self._dig(final_pos)
     self._last_steps.append(final_pos)
     if len(self._last_steps) > 6:
         self._last_steps.pop(0)
     return final_pos
示例#8
0
class Animal(Sprite, serializer.Simplifiable):
    """Base class for animals"""

    STEALTH = 0
    VISION_BONUS = 0
    VISION_RANGE_PENALTY = 10

    # sub-class must set this to the name of an image
    # file
    IMAGE_FILE = None

    SIMPLIFY = [
        'pos',
        'equipment',
        'accoutrements',
        'abode',
        'facing',
        'gameboard',
    ]

    def __init__(self, tile_pos, gameboard):
        # load images
        self._image_left = imagecache.load_image(self.IMAGE_FILE)
        self._image_right = imagecache.load_image(self.IMAGE_FILE,
                                                  ("right_facing", ))
        # Create the animal somewhere far off screen
        Sprite.__init__(self, self._image_left, (-1000, -1000))
        self.image_left = self._image_left.copy()
        self.image_right = self._image_right.copy()
        if hasattr(tile_pos, 'to_tile_tuple'):
            self.pos = tile_pos
        else:
            self.pos = Position(tile_pos[0], tile_pos[1], 0)
        self.equipment = []
        self.accoutrements = []
        self.abode = None
        self.facing = 'left'
        self.gameboard = gameboard

    @classmethod
    def make(cls):
        """Override default Simplifiable object creation."""
        return cls((0, 0), None)

    @classmethod
    def unsimplify(cls, *args, **kwargs):
        """Override default Simplifiable unsimplification."""
        obj = super(Animal, cls).unsimplify(*args, **kwargs)
        obj.redraw()
        return obj

    def loop(self, tv, _sprite):
        ppos = tv.tile_to_view(self.pos.to_tile_tuple())
        self.rect.x = ppos[0]
        self.rect.y = ppos[1]

    def die(self):
        """Play death animation, noises, whatever."""
        if hasattr(self, 'DEATH_SOUND'):
            sound.play_sound(self.DEATH_SOUND)
        if hasattr(self, 'DEATH_ANIMATION'):
            self.DEATH_ANIMATION(self.gameboard.tv, self.pos.to_tile_tuple())
        self._game_death()

    def _game_death(self):
        # Call appropriate gameboard cleanup here.
        pass

    def move(self):
        """Return a new position for the object"""
        # Default is not to move
        pass

    def attack(self):
        """Given the game state, attack a suitable target"""
        # Default is not to attack
        pass

    def set_pos(self, tile_pos):
        """Move an animal to the given tile_pos."""
        new_pos = Position(*tile_pos)
        self._fix_face(new_pos)
        self.pos = new_pos

    def _fix_face(self, facing_pos):
        """Set the face correctly"""
        if facing_pos.left_of(self.pos):
            self._set_image_facing('left')
        elif facing_pos.right_of(self.pos):
            self._set_image_facing('right')

    def _set_image_facing(self, facing):
        self.facing = facing
        if self.facing == 'left':
            self.setimage(self.image_left)
        elif self.facing == 'right':
            self.setimage(self.image_right)

    def equip(self, item):
        if equipment.is_equipment(item):
            self.equipment.append(item)
        elif equipment.is_accoutrement(item):
            self.accoutrements.append(item)
        self.redraw()

    def unequip(self, item):
        if equipment.is_equipment(item):
            self.equipment = [e for e in self.equipment if e != item]
        elif equipment.is_accoutrement(item):
            self.accoutrements = [e for e in self.accoutrements if e != item]
        self.redraw()

    def unequip_by_name(self, item_name):
        # only remove first match
        matches = [
            item for item in self.equipment + self.accoutrements
            if item.NAME == item_name
        ]
        if matches:
            self.unequip(matches[0])

    def get_stealth(self):
        stealth = self.STEALTH
        for eq in self.equipment:
            stealth_bonus = getattr(eq, "STEALTH_BONUS", 0)
            stealth += stealth_bonus
        return stealth

    def redraw(self):
        layers = [(self._image_left.copy(), self._image_right.copy(), 0)]
        if hasattr(self, 'EQUIPMENT_IMAGE_ATTRIBUTE'):
            for item in self.accoutrements + self.equipment:
                images = item.images(self.EQUIPMENT_IMAGE_ATTRIBUTE)
                if images:
                    layers.append(images)

        layers.sort(key=lambda l: l[2])

        # these always go on the bottom so that other layers don't get overwritten
        self.image_left = self._image_left.copy()
        self.image_right = self._image_right.copy()
        for l in layers:
            self.image_left.blit(l[0], (0, 0))
            self.image_right.blit(l[1], (0, 0))

        self._set_image_facing(self.facing)

    def weapons(self):
        return [e for e in self.equipment if equipment.is_weapon(e)]

    def surveillance_equipment(self):
        return [
            e for e in self.equipment if equipment.is_surveillance_equipment(e)
        ]

    def armour(self):
        return [e for e in self.equipment if equipment.is_armour(e)]

    def covers(self, tile_pos):
        return tile_pos[0] == self.pos.x and tile_pos[1] == self.pos.y

    def outside(self):
        return self.abode is None

    def damage(self):
        for a in self.armour():
            if not a.survive_damage():
                self.unequip(a)
            return True
        self.die()
        return False
示例#9
0
 def set_pos(self, tile_pos):
     """Move an animal to the given tile_pos."""
     new_pos = Position(*tile_pos)
     self._fix_face(new_pos)
     self.pos = new_pos
示例#10
0
import random

from pgu.vid import Sprite

import imagecache
import tiles
from misc import Position
import sound
import equipment
import animations
import serializer
import constants

NEIGHBOUR_4 = [
    Position(-1, 0),
    Position(1, 0),
    Position(0, 1),
    Position(0, -1)
]

NEIGHBOUR_8 = [
    Position(-1, 0),
    Position(1, 0),
    Position(0, 1),
    Position(0, -1),
    Position(1, 1),
    Position(1, -1),
    Position(-1, 1),
    Position(-1, -1)
]