Commits

Jason Scheirer committed 689d690

Works-in-progress: parks, girder skeletons in buildings

Comments (0)

Files changed (1)

 
 import abc
 import random
+import itertools
 
 import pymclevel
 
 materials = pymclevel.namedMaterials['Alpha']
 
 class Building(object):
+    building_type_registry = []
+    @classmethod
+    def register_building_type(cls, bt):
+        cls.building_type_registry.append(bt)
+        return bt
     def __repr__(self):
         return "<Building {0} {1}>".format(self.__class__.__name__,
                                            self.bbox)
     def __init__(self, bbox, griditem, orientation=-1):
-        self.bbox = bbox
+        self.bbox = pymclevel.mclevel.BoundingBox(bbox)
         self.griditem = griditem
         if orientation == -1:
-            orientation = random.choice([0, 1, 2, 3])
+            orientation = 1 #random.choice([0, 1, 2, 3])
         self.orientation = orientation
     # Actually lay down the building onto the map
     @abc.abstractmethod
     # cycle
     max_uses = -1
 
+@Building.register_building_type
+class Park(Building):
+    @staticmethod
+    def can_use_here(width, height, depth):
+        return 5 < height < 24
+    def make_building(self, level):
+        self.bbox.miny += 1
+        self.bbox.maxy = self.bbox.miny + 1
+        level.fillBlocks(self.bbox, materials.Flower)
+
+@Building.register_building_type
 class Skyscraper(Building):
     def __init__(self, bbox, griditem, orientation=-1):
         self.stone = random.choice([materials.Cobblestone,
         self.flooring = random.choice([materials.Stone,
                                        materials.WoodPlanks])
         super(Skyscraper, self).__init__(bbox, griditem, orientation)
+    @staticmethod
+    def can_use_here(width, height, depth):
+        return height > 5
     def make_building(self, level):
         Glass = materials.Glass
         Air = materials.Air
                         if self.flooring is materials.Stone
                         else materials.WoodenStairs)
         Door = materials.WoodenDoor
+        Iron = materials.BlockofIron
         bbox = pymclevel.mclevel.BoundingBox(self.bbox)
         level.fillBlocks(bbox, Air)
         bbox.miny += 1 # Meet sidewalk level
         bbox.maxy -= (bbox.maxy - bbox.miny) % 4
+        centerx = bbox.minx + ((bbox.maxx - bbox.minx) / 2)
+        centerz = bbox.minz + ((bbox.maxz - bbox.minz) / 2)
         stories = (bbox.maxy - bbox.miny) / 4
         glasswall = pymclevel.mclevel.BoundingBox(bbox)
         glasswall.miny += 1
         # Make glass box
         for glassbbox in (northwall, southwall, eastwall, westwall):
             level.fillBlocks(glassbbox, Glass)
-        northwall.minz = northwall.maxz - 1
-        southwall.maxz = southwall.minz + 1
-        eastwall.maxx = eastwall.minx + 1
-        westwall.minx = westwall.maxx - 1
-        # Make corners of building solid
-        for edge in (northwall, southwall, eastwall, westwall):
-            level.fillBlocks(edge, self.stone)
-        centerx = bbox.minx + ((bbox.maxx - bbox.minx) / 2)
-        centerz = bbox.minz + ((bbox.maxz - bbox.minz) / 2)
         # Add a floor for each story
         for story in xrange(stories + 1):
             newbbox = pymclevel.mclevel.BoundingBox(bbox)
             floorbox.maxx -= 1
             floorbox.minz += 1
             floorbox.maxz -= 1
+            supportbox = pymclevel.mclevel.BoundingBox(floorbox)
+            supportbox.miny -= 1
+            level.fillBlocks(supportbox, Iron)
+            supportbox.minx += 1
+            supportbox.minz += 1
+            supportbox.maxx -= 1
+            supportbox.maxz -= 1
+            level.fillBlocks(supportbox, Air)
             level.fillBlocks(floorbox, self.flooring)
             # Add lights to floor below, then put in stairs
             if story > 0:
+                # Fill with lights
                 lightbbox = pymclevel.mclevel.BoundingBox(floorbox)
                 lightbbox.minz += 1
                 lightbbox.maxz -= 1
                         level.setBlockAt(xoffset + 1, yoffset, zoffset, Torch.ID)
                         level.setBlockDataAt(xoffset + 1, yoffset, zoffset, 1)
 
+                # Add upward stair
                 offseta, offsetb = [0, 0, 0, 0], range(-2, 2)
 
                 if self.orientation in (0, 2):
                                          yoffset - (yo - 1),
                                          centerz + zoffset,
                                          self.orientation)
+                # Clear block right in front, add girders
+                if xoffset < 0:
+                    xoffset -= 1
+                elif xoffset:
+                    xoffset += 1
+                if zoffset < 0:
+                    zoffset -= 1
+                elif zoffset:
+                    zoffset += 1
+                for eyo in range(3):
+                    level.setBlockAt(centerx + xoffset,
+                                     yoffset + 1 - eyo,
+                                     centerz + zoffset,
+                                     Air.ID)
+                    for xpos, zpos in itertools.product((lightbbox.minx,
+                                                         lightbbox.maxx),
+                                                        (lightbbox.minz,
+                                                         lightbbox.maxz)):
+                        level.setBlockAt(xpos,
+                                         yoffset + 1 - eyo,
+                                         zpos,
+                                         Iron.ID)
+
+        northwall.minz = northwall.maxz - 1
+        southwall.maxz = southwall.minz + 1
+        eastwall.maxx = eastwall.minx + 1
+        westwall.minx = westwall.maxx - 1
+        for edge in (northwall, southwall, eastwall, westwall):
+            level.fillBlocks(edge, self.stone)
         # Add a rooftop guard block
         newbbox.maxy += 1
         newbbox.miny += 1
         if self.orientation in (2, 3):
             px, pz = centerx, bbox.minz if self.orientation == 2 else bbox.maxz - 1
         else:
-            px, pz = bbox.minx if self.orientation == 0 else bbox.maxx, centerz
+            px, pz = bbox.minx if self.orientation == 0 else bbox.maxx - 1, centerz
+        doordata = [1, 1, 1, 1]
         for yoffset in (1, 2):
             #print (px, bbox.miny + yoffset, pz, Lighting.ID)
             level.setBlockAt(px, bbox.miny + yoffset, pz, Door.ID)
             level.setBlockDataAt(px,
                                  bbox.miny + yoffset,
                                  pz,
-                                 (8 if yoffset == 2 else 0))
+                                 (8 if yoffset == 1 else 0) &
+                                 doordata[self.orientation])
 
 class Buildings(object):
     def __init__(self, grid, origin, node_length, level):
     def put_buildings(self, noisy = False):
         for item in self.grid:
             bbox = self._bbox_for_building(item)
-            building = Skyscraper(bbox, item)
-            if noisy:
-                print "     Building", building
-            building.make_building(self.level)
+            building_types = [b for b in Building.building_type_registry
+                              if b.can_use_here(*bbox.size)]
+            if building_types:
+                bt = random.choice(building_types)
+                building = bt(bbox, item)
+                if noisy:
+                    print "    Building", building
+                building.make_building(self.level)