changeset 378:71f5897ac5ef

Fences are now buildings, with appropriate (but ugly) UI changes.
author Jeremy Thurgood <firxen@gmail.com>
date Sat, 24 Oct 2009 19:08:54 +0000
parents 0dc9d17c689e
children a8a7ada27fa2
files data/cursors/repair_cursor.xbm gamelib/animal.py gamelib/buildings.py gamelib/constants.py gamelib/cursors.py gamelib/gameboard.py
diffstat 6 files changed, 149 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/cursors/repair_cursor.xbm	Sat Oct 24 19:08:54 2009 +0000
@@ -0,0 +1,29 @@
+/*
+ * img_data = [
+ *     "................",
+ *     ".....###........",
+ *     "....####........",
+ *     "...#####........",
+ *     "..#####.........",
+ *     ".#######........",
+ *     "######.##.......",
+ *     ".###.#####......",
+ *     "..#...##.##.....",
+ *     ".......#####....",
+ *     "........##.##...",
+ *     ".........#####..",
+ *     "..........##.##.",
+ *     "...........#####",
+ *     "............##.#",
+ *     ".............##.",
+ *     ]
+ */
+
+#define repair_cursor_width 16
+#define repair_cursor_height 16
+#define repair_cursor_hot_x 4
+#define repair_cursor_hot_y 4
+static unsigned char repair_cursor_bits[] = {
+   0x00, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0xfe, 0x00,
+   0xbf, 0x01, 0xee, 0x03, 0xc4, 0x06, 0x80, 0x0f, 0x00, 0x1b, 0x00, 0x3e,
+   0x00, 0x6c, 0x00, 0xf8, 0x00, 0xb0, 0x00, 0x60 };
--- a/gamelib/animal.py	Tue Oct 13 20:35:05 2009 +0000
+++ b/gamelib/animal.py	Sat Oct 24 19:08:54 2009 +0000
@@ -425,7 +425,7 @@
 
     def _make_hole(self, gameboard):
         """Make a hole in the fence"""
-        gameboard.tv.set(self.dig_pos.to_tuple(), gameboard.BROKEN_FENCE)
+        gameboard.get_building(self.dig_pos.to_tuple()).damage(gameboard.tv)
         self.dig_pos = None
 
     def move(self, gameboard):
@@ -505,7 +505,9 @@
 
     def _make_hole(self, gameboard):
         """The Rinkhals eats fences"""
-        gameboard.tv.set(self.dig_pos.to_tuple(), gameboard.GRASSLAND)
+        fence = gameboard.get_building(self.dig_pos.to_tuple())
+        fence.remove(gameboard.tv)
+        gameboard.remove_building(fence)
         self.dig_pos = None
 
     def damage(self, gameboard):
--- a/gamelib/buildings.py	Tue Oct 13 20:35:05 2009 +0000
+++ b/gamelib/buildings.py	Sat Oct 24 19:08:54 2009 +0000
@@ -64,39 +64,59 @@
     GRASSLAND = tiles.REVERSE_TILE_MAP['grassland']
     MODIFY_KNIFE_RANGE = lambda s, x: 0
     MODIFY_GUN_RANGE = lambda s, x: -1
+    BREAKABLE = False
+    ABODE = False
 
     def __init__(self, pos):
         """Initial image, tile vid position, size and tile number for building."""
-        self.day_image = imagecache.load_image(self.IMAGE)
-        self.night_image = imagecache.load_image(self.IMAGE, ('night',))
-        self.selected_image = imagecache.load_image(self.SELECTED_IMAGE)
+        self._set_images()
         self.pos = pos
         self.size = self.SIZE
         self.tile_no = self.TILE_NO
         self._buy_price = self.BUY_PRICE
         self._sell_price = self.SELL_PRICE
+        self._repair_price = getattr(self, 'REPAIR_PRICE', None)
         self._sun_on = True
         self._font = pygame.font.SysFont('Vera', 30, bold=True)
-        self._font_image = pygame.Surface(self.day_image.get_size(), flags=SRCALPHA)
+        self._font_image = pygame.Surface(self.images['fixed']['day'].get_size(), flags=SRCALPHA)
         self._font_image.fill((0, 0, 0, 0))
+        self._broken = False
 
         self._floors = []
-        for f in range(self.FLOORS):
-            places = []
-            for j in range(self.size[1]):
-                row = []
-                for i in range(self.size[0]):
-                    row.append(Place(self, (i, j)))
-                places.append(row)
-            floor = Floor("Floor %s" % (f+1,), places)
-            self._floors.append(floor)
+        if self.FLOORS:
+            for f in range(self.FLOORS):
+                places = []
+                for j in range(self.size[1]):
+                    row = []
+                    for i in range(self.size[0]):
+                        row.append(Place(self, (i, j)))
+                    places.append(row)
+                floor = Floor("Floor %s" % (f+1,), places)
+                self._floors.append(floor)
 
-        # 0: the main iamge
+        # 0: the main image
         # 1: above, -1: below
-        self.draw_stack = {"main": (0, self.day_image)}
+        self.draw_stack = {"main": (0, self.images['fixed']['day'])}
 
         # Create the building somewhere far off screen
-        Sprite.__init__(self, self.day_image, (-1000, -1000))
+        Sprite.__init__(self, self.images['fixed']['day'], (-1000, -1000))
+
+    def _set_images(self):
+        self.images = {'fixed': {
+            'day': imagecache.load_image(self.IMAGE),
+            'night': imagecache.load_image(self.IMAGE, ('night',)),
+            'selected': imagecache.load_image(self.SELECTED_IMAGE),
+            }}
+        if self.BREAKABLE:
+            self.images['broken'] = {
+                'day': imagecache.load_image(self.IMAGE_BROKEN),
+                'night': imagecache.load_image(self.IMAGE_BROKEN, ('night',)),
+                'selected': imagecache.load_image(self.SELECTED_IMAGE_BROKEN),
+                }
+
+    def _set_main_image(self):
+        image_set = self.images[{True: 'broken',False: 'fixed'}[self._broken]]
+        self._replace_main(image_set[{True: 'day', False: 'night'}[self._sun_on]])
 
     def _redraw(self):
         items = self.draw_stack.values()
@@ -168,6 +188,27 @@
         return (xpos <= tile_pos[0] < xpos + xsize) and \
             (ypos <= tile_pos[1] < ypos + ysize)
 
+    def broken(self):
+        return self._broken
+
+    def damage(self, tv):
+        if not self.BREAKABLE:
+            return False
+        self._broken = True
+        self._sell_price = self.SELL_PRICE_BROKEN
+        self.tile_no = self.TILE_NO_BROKEN
+        for tile_pos in self.tile_positions():
+            tv.set(tile_pos, self.tile_no)
+        self._set_main_image()
+
+    def repair(self, tv):
+        self._broken = False
+        self._sell_price = self.SELL_PRICE
+        self.tile_no = self.TILE_NO
+        for tile_pos in self.tile_positions():
+            tv.set(tile_pos, self.tile_no)
+        self._set_main_image()
+
     def remove(self, tv):
         """Remove the building from its current position."""
         # remove tile
@@ -180,18 +221,18 @@
     def sell_price(self):
         return self._sell_price
 
+    def repair_price(self):
+        return self._repair_price
+
     def selected(self, selected):
         if selected:
-            self._replace_main(self.selected_image)
+            self._replace_main(self.images[{True: 'broken',False: 'fixed'}[self._broken]]['selected'])
         else:
-            self.sun(self._sun_on)
+            self._set_main_image()
 
     def sun(self, sun_on):
         self._sun_on = sun_on
-        if sun_on:
-            self._replace_main(self.day_image)
-        else:
-            self._replace_main(self.night_image)
+        self._set_main_image()
 
     def update_occupant_count(self):
         count = len(list(self.occupants()))
@@ -234,7 +275,10 @@
             if place.occupant is not None:
                 yield place.occupant
 
-class HenHouse(Building):
+class Abode(Building):
+    ABODE = True
+
+class HenHouse(Abode):
     """A HenHouse."""
 
     TILE_NO = tiles.REVERSE_TILE_MAP['henhouse']
@@ -258,7 +302,7 @@
     NAME = 'Hendominium'
     FLOORS = 2
 
-class GuardTower(Building):
+class GuardTower(Abode):
     """A GuardTower."""
 
     TILE_NO = tiles.REVERSE_TILE_MAP['guardtower']
@@ -276,6 +320,25 @@
     MODIFY_VISION_BONUS = lambda s, x: x+10
     MODIFY_VISION_RANGE_PENALTY = lambda s, x: x-2
 
+class Fence(Building):
+    """A fence."""
+
+    TILE_NO = tiles.REVERSE_TILE_MAP['fence']
+    TILE_NO_BROKEN = tiles.REVERSE_TILE_MAP['broken fence']
+    BREAKABLE = True
+    BUY_PRICE = 50
+    SELL_PRICE = 25
+    REPAIR_PRICE = 25
+    SELL_PRICE_BROKEN = 5
+    SIZE = (1, 1)
+    IMAGE = 'tiles/fence.png'
+    SELECTED_IMAGE = 'tiles/fence.png'
+    IMAGE_BROKEN = 'tiles/broken_fence.png'
+    SELECTED_IMAGE_BROKEN = 'tiles/broken_fence.png'
+    NAME = 'Fence'
+    FLOORS = 0
+
+
 def is_building(obj):
     """Return true if obj is a build class."""
     return getattr(obj, "IS_BUILDING", False) and hasattr(obj, "NAME")
--- a/gamelib/constants.py	Tue Oct 13 20:35:05 2009 +0000
+++ b/gamelib/constants.py	Sat Oct 24 19:08:54 2009 +0000
@@ -39,7 +39,7 @@
 TOOL_SELL_CHICKEN = 1
 TOOL_SELL_EGG = 2
 TOOL_SELL_BUILDING = 3
-TOOL_BUY_FENCE = 4
+TOOL_REPAIR_BUILDING = 4
 TOOL_PLACE_ANIMALS = 5
 TOOL_LOGGING = 6
 TOOL_SELL_EQUIPMENT = 7
--- a/gamelib/cursors.py	Tue Oct 13 20:35:05 2009 +0000
+++ b/gamelib/cursors.py	Sat Oct 24 19:08:54 2009 +0000
@@ -14,6 +14,7 @@
 for tag, filename in [
         ('chicken', 'cursors/chkn.xbm'),
         ('sell', 'cursors/sell_cursor.xbm'),
+        ('repair', 'cursors/repair_cursor.xbm'),
         ]:
     path = data.filepath(filename)
     # pygame 1.8 needs the file twice to do the right thing
--- a/gamelib/gameboard.py	Tue Oct 13 20:35:05 2009 +0000
+++ b/gamelib/gameboard.py	Sat Oct 24 19:08:54 2009 +0000
@@ -77,13 +77,13 @@
         self.add_counter(mklabel("Eggs:"), self.egg_counter)
         self.add_counter(icons.CHKN_ICON, self.chicken_counter)
         self.add_counter(icons.KILLED_FOX, self.killed_foxes)
-        self.add_spacer(15)
+        self.add_spacer(5)
 
         self.add_tool_button("Move Hen", constants.TOOL_PLACE_ANIMALS,
                 None, cursors.cursors['select'])
         self.add_tool_button("Cut Trees", constants.TOOL_LOGGING,
                 constants.LOGGING_PRICE, cursors.cursors['ball'])
-        self.add_spacer(15)
+        self.add_spacer(5)
 
         self.add_heading("Sell ...")
         self.add_tool_button("Chicken", constants.TOOL_SELL_CHICKEN,
@@ -94,14 +94,10 @@
                 None, cursors.cursors['sell'])
         self.add_tool_button("Equipment", constants.TOOL_SELL_EQUIPMENT,
                 None, cursors.cursors['sell'])
-        self.add_spacer(15)
+        self.add_spacer(5)
 
         self.add_heading("Buy ...")
 
-        self.add_tool_button("Fence", constants.TOOL_BUY_FENCE,
-                "%s/%s" % (constants.BUY_PRICE_FENCE,
-                           constants.REPAIR_PRICE_FENCE))
-
         for building_cls in buildings.BUILDINGS:
             self.add_tool_button(building_cls.NAME.title(), building_cls,
                     None, cursors.cursors.get('build', None))
@@ -112,9 +108,12 @@
                     equipment_cls.BUY_PRICE,
                     cursors.cursors.get('buy', None))
 
-        self.add_spacer(10)
+        self.add_spacer(5)
+        self.add_tool_button("Repair", constants.TOOL_REPAIR_BUILDING, None, cursors.cursors['repair'])
+
+        self.add_spacer(5)
         self.add_tool("Price Reference", self.show_prices)
-        self.add_spacer(20)
+        self.add_spacer(10)
 
         self.fin_tool = self.add_tool("Finished Day", self.day_done)
 
@@ -163,32 +162,29 @@
 
         tbl = gui.Table()
         tbl.tr()
-        doc = gui.Document(width=380)
+        doc = gui.Document(width=510)
         space = doc.style.font.size(" ")
-        for header in ['Item', 'Buy Price', 'Sell Price']:
+        for header in ['Item', 'Buy Price', 'Sell Price', 'Repair Price']:
             doc.add(make_box(header))
         doc.br(space[1])
         for building in buildings.BUILDINGS:
             doc.add(make_box(building.NAME))
             doc.add(make_box('%d' % building.BUY_PRICE))
             doc.add(make_box('%d' % building.SELL_PRICE))
+            if building.BREAKABLE:
+                doc.add(make_box('%d' % building.REPAIR_PRICE))
+            else:
+                doc.add(make_box('N/A'))
             doc.br(space[1])
         for equip in equipment.EQUIPMENT:
             doc.add(make_box(equip.NAME))
             doc.add(make_box('%d' % equip.BUY_PRICE))
             doc.add(make_box('%d' % equip.SELL_PRICE))
+            doc.add(make_box('N/A'))
             doc.br(space[1])
 
-        doc.add(make_box("Fence"))
-        doc.add(make_box('%d' % constants.BUY_PRICE_FENCE))
-        doc.add(make_box('%d' % constants.SELL_PRICE_FENCE))
-
-        doc.add(make_box("Repair Fence"))
-        doc.add(make_box('%d' % constants.REPAIR_PRICE_FENCE))
-        doc.add(make_box(''))
-
         fix_widths(doc)
-        for word in "Damaged equipment or broken fences will be sold for" \
+        for word in "Damaged equipment or buildings will be sold for" \
                 " less than the sell price.".split():
             doc.add(gui.Label(word))
             doc.space(space)
@@ -385,8 +381,6 @@
             sprite_curs = sprite_cursor.SpriteCursor(tool.IMAGE, self.tv, tool.BUY_PRICE)
         elif equipment.is_equipment(tool):
             sprite_curs = sprite_cursor.SpriteCursor(tool.CHICKEN_IMAGE_FILE, self.tv)
-        elif tool == constants.TOOL_BUY_FENCE:
-            sprite_curs = sprite_cursor.SpriteCursor("tiles/fence.png", self.tv)
         self.set_cursor(cursor, sprite_curs)
 
     def set_cursor(self, cursor=None, sprite_curs=None):
@@ -441,12 +435,12 @@
             self.sell_egg(self.tv.screen_to_tile(e.pos))
         elif self.selected_tool == constants.TOOL_PLACE_ANIMALS:
             self.place_animal(self.tv.screen_to_tile(e.pos))
-        elif self.selected_tool == constants.TOOL_BUY_FENCE:
-            self.buy_fence(self.tv.screen_to_tile(e.pos))
         elif self.selected_tool == constants.TOOL_SELL_BUILDING:
             self.sell_building(self.tv.screen_to_tile(e.pos))
         elif self.selected_tool == constants.TOOL_SELL_EQUIPMENT:
             self.sell_equipment(self.tv.screen_to_tile(e.pos))
+        elif self.selected_tool == constants.TOOL_REPAIR_BUILDING:
+            self.repair_building(self.tv.screen_to_tile(e.pos))
         elif self.selected_tool == constants.TOOL_LOGGING:
             self.logging_forest(self.tv.screen_to_tile(e.pos))
         elif buildings.is_building(self.selected_tool):
@@ -540,7 +534,7 @@
                 pygame.mouse.set_cursor(*cursors.cursors['chicken'])
             return
         building = self.get_building(tile_pos)
-        if building:
+        if building and building.ABODE:
             if self.animal_to_place:
                 try:
                     place = building.first_empty_place()
@@ -686,33 +680,6 @@
 
         self.open_dialog(tbl, close_callback=close_callback)
 
-    def buy_fence(self, tile_pos):
-        this_tile = self.tv.get(tile_pos)
-        if this_tile not in [self.GRASSLAND, self.BROKEN_FENCE]:
-            return
-        if this_tile == self.GRASSLAND:
-            cost = constants.BUY_PRICE_FENCE
-        else:
-            cost = constants.REPAIR_PRICE_FENCE
-        if any((chicken.pos.x, chicken.pos.y) == tile_pos for chicken in self.chickens):
-            return
-
-        if self.cash < cost:
-            print "You can't afford a fence."
-            return
-        self.add_cash(-cost)
-        self.tv.set(tile_pos, self.FENCE)
-
-    def sell_fence(self, tile_pos):
-        this_tile = self.tv.get(tile_pos)
-        if this_tile not in [self.FENCE, self.BROKEN_FENCE]:
-            return
-        if this_tile == self.FENCE:
-            self.add_cash(constants.SELL_PRICE_FENCE)
-        elif this_tile == self.BROKEN_FENCE:
-            self.add_cash(constants.SELL_PRICE_BROKEN_FENCE)
-        self.tv.set(tile_pos, self.GRASSLAND)
-
     def logging_forest(self, tile_pos):
         if self.tv.get(tile_pos) != self.WOODLAND:
             return
@@ -749,7 +716,7 @@
         chicken = self.get_outside_chicken(tile_pos)
         if chicken is None:
             building = self.get_building(tile_pos)
-            if building is None:
+            if not (building and building.ABODE):
                 return
             # Bounce through open dialog once more
             self.open_building_dialog(building, do_equip)
@@ -757,8 +724,6 @@
             do_equip(chicken)
 
     def sell_building(self, tile_pos):
-        if self.tv.get(tile_pos) in [self.FENCE, self.BROKEN_FENCE]:
-            return self.sell_fence(tile_pos)
         building = self.get_building(tile_pos)
         if building is None:
             return
@@ -770,6 +735,13 @@
         building.remove(self.tv)
         self.remove_building(building)
 
+    def repair_building(self, tile_pos):
+        building = self.get_building(tile_pos)
+        if not (building and building.broken()):
+            return
+        self.add_cash(-building.repair_price())
+        building.repair(self.tv)
+
     def sell_equipment(self, tile_pos):
         x, y = 0, 0
         def do_sell(chicken, update_button=None):