# HG changeset patch # User Simon Cross # Date 1251926884 0 # Node ID 2e3a05b9594d768180faf4f7747055fb9fed35d5 # Parent 69fd96eafde827b6ba12cb6a36fe4f78d9b961a3 Chickens in buildings\! diff -r 69fd96eafde8 -r 2e3a05b9594d gamelib/animal.py --- a/gamelib/animal.py Wed Sep 02 21:14:05 2009 +0000 +++ b/gamelib/animal.py Wed Sep 02 21:28:04 2009 +0000 @@ -57,6 +57,9 @@ 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 + class Chicken(Animal): """A chicken""" @@ -114,9 +117,6 @@ sound.play_sound("kill-fox.ogg") gameboard.kill_fox(fox) - def outside(self): - return self.abode is None - class Egg(Animal): """An egg""" diff -r 69fd96eafde8 -r 2e3a05b9594d gamelib/buildings.py --- a/gamelib/buildings.py Wed Sep 02 21:14:05 2009 +0000 +++ b/gamelib/buildings.py Wed Sep 02 21:28:04 2009 +0000 @@ -5,6 +5,47 @@ import imagecache import tiles +class Place(object): + """Space within a building that can be occupied.""" + + def __init__(self, building, offset): + self.occupant = None + self.building = building + self.offset = offset + + def set_occupant(self, occupant): + self.clear_occupant() + self.occupant = occupant + self.occupant.abode = self + + def clear_occupant(self): + if self.occupant is not None: + self.occupant.abode = None + self.occupant = None + + def get_pos(self): + bpos = self.building.pos + return (bpos[0] + self.offset[0], bpos[1] + self.offset[1]) + +class Floor(object): + """A set of places within a building. Places on a + floor are organised into rows and columns. + """ + + def __init__(self, title, places): + self.title = title # str + self.places = places # list of lists of places + + def rows(self): + for row in self.places: + yield row + + def width(self): + return max(len(row) for row in self.places) + +class BuildingFullError(Exception): + pass + class Building(Sprite): """Base class for buildings""" @@ -20,7 +61,17 @@ self.tile_no = self.TILE_NO self._buy_price = self.BUY_PRICE self._sell_price = self.SELL_PRICE - self._occupants = set() + + self._floors = [] + for f in range(self.FLOORS): + places = [] + for i in range(self.size[0]): + row = [] + for j in range(self.size[1]): + row.append(Place(self, (i, j))) + places.append(row) + floor = Floor("Floor %s" % (f+1,), places) + self._floors.append(floor) # Create the building somewhere far off screen Sprite.__init__(self, self.day_image, (-1000, -1000)) @@ -86,20 +137,32 @@ else: self.setimage(self.night_image) - def occupants(self): - """Return list of buildings occupants.""" - return list(self._occupants) + def floors(self): + return self._floors + + def places(self): + for floor in self._floors: + for row in floor.rows(): + for place in row: + yield place + + def max_floor_width(self): + return max(floor.width() for floor in self._floors) + + def first_empty_place(self): + for place in self.places(): + if place.occupant is None: + return place + raise BuildingFullError() def add_occupant(self, occupant): - if occupant.abode is not None: - occupant.abode.remove_occupant(occupant) - occupant.abode = self - self._occupants.add(occupant) + place = self.first_empty_place() + place.set_occupant(occupant) - def remove_occupant(self, occupant): - if occupant in self._occupants: - self._occupants.remove(occupant) - occupant.abode = None + def occupants(self): + for place in self.places(): + if place.occupant is not None: + yield place.occupant class HenHouse(Building): """A HenHouse.""" @@ -110,7 +173,14 @@ SIZE = (3, 2) IMAGE = 'sprites/henhouse.png' NAME = 'Hen House' + FLOORS = 1 +class DoubleStoryHenHouse(HenHouse): + """A double story hen house.""" + BUY_PRICE = 300 + SELL_PRICE = 150 + NAME = 'Hendominium' + FLOORS = 2 class GuardTower(Building): """A GuardTower.""" @@ -121,6 +191,7 @@ SIZE = (2, 2) IMAGE = 'sprites/watchtower.png' NAME = 'Watch Tower' + FLOORS = 1 def is_building(obj): """Return true if obj is a build class.""" diff -r 69fd96eafde8 -r 2e3a05b9594d gamelib/gameboard.py --- a/gamelib/gameboard.py Wed Sep 02 21:14:05 2009 +0000 +++ b/gamelib/gameboard.py Wed Sep 02 21:28:04 2009 +0000 @@ -233,24 +233,26 @@ self.animal_to_place = None else: self.animal_to_place = chicken - print "Selected animal %r" % (self.animal_to_place,) return building = self.get_building(tile_pos) if building: - # XXX: quick hack so egg loop triggers - if self.animal_to_place: - building.add_occupant(self.animal_to_place) - if self.animal_to_place in self.tv.sprites: - self.tv.sprites.remove(self.animal_to_place) - self.animal_to_place = None - self.open_building_dialog(building) + self.open_building_dialog(building) return if self.tv.get(tile_pos) == self.GRASSLAND: if self.animal_to_place is not None: occupant = self.animal_to_place if occupant.abode is not None: - occupant.abode.remove_occupant(occupant) + occupant.abode.clear_occupant() occupant.set_pos(tile_pos) + self.set_visibility(occupant) + + def set_visibility(self, chicken): + if chicken.outside(): + if chicken not in self.tv.sprites: + self.tv.sprites.append(chicken) + else: + if chicken in self.tv.sprites: + self.tv.sprites.remove(chicken) def open_dialog(self, widget): """Open a dialog for the given widget. Add close button.""" @@ -273,13 +275,50 @@ def open_building_dialog(self, building): """Create dialog for manipulating the contents of a building.""" + def select_occupant(place, button): + """Select occupant in place.""" + self.animal_to_place = place.occupant + + def set_occupant(place, button): + """Set occupant of a given place.""" + if self.animal_to_place is not None: + button.value = icons.CHKN_NEST_ICON + button.disconnect(gui.CLICK, set_occupant) + button.connect(gui.CLICK, select_occupant, place, button) + + old_abode = self.animal_to_place.abode + if id(old_abode) in place_button_map: + old_button = place_button_map[id(old_abode)] + old_button.value = icons.EMPTY_NEST_ICON + old_button.disconnect(gui.CLICK, select_occupant) + old_button.connect(gui.CLICK, set_occupant, place, button) + + chicken = self.animal_to_place + place.set_occupant(chicken) + chicken.set_pos(place.get_pos()) + self.set_visibility(self.animal_to_place) + + place_button_map = {} + width, height = pygame.display.get_surface().get_size() tbl = gui.Table() - for row in range(building.size[0]): + columns = building.max_floor_width() + kwargs = { 'style': { 'padding_left': 10, 'padding_bottom': 10 }} + for floor in building.floors(): + tbl.tr() + tbl.td(gui.Button(floor.title), colspan=columns, align=-1, **kwargs) tbl.tr() - for col in range(building.size[1]): - button = gui.Button("%s, %s" % (row, col)) - tbl.td(button) + for row in floor.rows(): + tbl.tr() + for place in row: + if place.occupant is None: + button = gui.Button(icons.EMPTY_NEST_ICON) + button.connect(gui.CLICK, set_occupant, place, button) + else: + button = gui.Button(icons.CHKN_NEST_ICON) + button.connect(gui.CLICK, select_occupant, place, button) + place_button_map[id(place)] = button + tbl.td(button, **kwargs) self.open_dialog(tbl) @@ -401,8 +440,11 @@ new_chick = chicken.hatch() if new_chick: self.eggs -= 1 - building.add_occupant(new_chick) - self.add_chicken(new_chick) + try: + building.add_occupant(new_chick) + self.add_chicken(new_chick) + except buildings.BuildingFullError: + print "Building full." self.toolbar.update_egg_counter(self.eggs) def kill_fox(self, fox): @@ -423,7 +465,7 @@ self.eggs -= 1 self.toolbar.update_egg_counter(self.eggs) if chick.abode: - chick.abode.remove_occupant(chick) + chick.abode.clear_occupant() self.toolbar.update_chicken_counter(len(self.chickens)) if chick in self.tv.sprites: if chick.outside():