def create(generatorName, level, areas):
    log("Generating a " + generatorName)
    while len(areas) > 0:
        (box, availableFlag) = areas.pop()
        width, height, depth = getDimensionsFromBox(box)
        log("Generating a " + generatorName + " at " + str(box))

        MINW = width - 2
        MIND = depth - 2
        SEED = randint(1000000000, 9999999999)
        R = Random(SEED)  # Seed goes here
        firstBox = (box.minx, box.minz, box.maxx - box.minx,
                    box.maxz - box.minz)
        h = box.maxy - box.miny
        boxes = [firstBox]
        for i in xrange(0, randint(1, 5)):
            boxes = chopUpBoxes2D(R, boxes, MINW, MIND)

        for (x, z, w, d) in boxes:
            Farmland(level, BoundingBox((x, box.miny, z), (w, h, d)))
Example #2
0
def create(generatorName, level, areas):
    # NOTE: Assumption is that this level and box object starts from 0,0,0
    # i.e. we're working with a fresh scratchpad schematic and not directly against the world level
    # simplifies calculation of where to put rooms
    log("Generating a " + generatorName)
    while len(areas) > 0:
        (box, availableFlag) = areas.pop()
        width, height, depth = getDimensionsFromBox(box)
        log("Generating a " + generatorName + " at " + str(box))

        # A house is a collection of rooms.
        # Start with a floorplan to determine the room layout
        # - each room is a box-like thing with a pitched roof
        # - once assembled doors can be punched through
        # - Windows projected from the exterior faces of the box
        # - Chimney

        blueprint = [
            "Bedroom", "Kitchen", "LivingRoom", "Bedroom", "Tower", "Bedroom",
            "LivingRoom", "Bedroom", "Bedroom", "LivingRoom", "Bedroom",
            "Bedroom", "Tower"
        ]

        log("Making a floor plan")
        plan = makeFloorPlan(box, blueprint)
        log("Placing the rooms")
        for room in plan.rooms:
            room.placeRoom(level)  # Floor, walls, ceilings
            #furnishRoom(level,room)

        placeWindows(level)
        placeDoors(level)
        placeLighting(level)

        for room in plan.rooms:
            room.furnish(level)
Example #3
0
def create(generatorName, level, areas):
    # This module creates a settlement in the selection based on the availableAreas.
    SMALL = 8
    MEDIUM = 16
    LARGE = 32

    settlementA = [
        "House", "FarmLand", "House", "TownSquare", "Tower"
    ]  #["TownSquare","TownHall","Farm","House"] # Add any generator types here
    for i in xrange(0, randint(30, 100)):
        randval = randint(1, 10)
        if randval == 1:
            settlementA.append("Tower")
        if randval == 2:
            settlementA.append("House")
        else:
            settlementA.append("FarmLand")
    settlements = [
        settlementA
    ]  # In reality you'll mix this up with different blueprints, probably based on biome type

    # Optional: Check bounds and whether we can do anything

    chosenVariant = settlements[randint(0,
                                        len(settlements) -
                                        1)]  # Pick one at random

    BADFOUNDATIONBLOCKS = [8, 9, 10, 11]
    plotAreas = []
    for (box, flag) in areas:
        (heightMap, minHeight, maxHeight, layerMap, blocks,
         blockIDs) = profileCell(level, (box.minx, box.miny, box.minz),
                                 (box.maxx, box.maxy, box.maxz))
        edgeMap = mapEdges(heightMap, 1)
        cells = identifyContiguousAreas(edgeMap)
        print cells
        # The cells list is (posx,posy,size). So we are going to build a new set of boxes and use them to generate the settlement
        for (x, y, size) in cells:
            if False:  # Debug
                col = randint(0, 15)
                for ix in xrange(box.minx + x, box.minx + x + size):
                    for iz in xrange(box.minz + y, box.minz + y + size):
                        setBlock(level, ix, box.maxy - 3, iz, (35, col))
                        # print ix,box.maxy-3,iz
            if size >= SMALL:  # Minimum size to generate against
                # Check if this area has water or lava in it, in which case we can't build here
                okToBuild = True
                badFoundationCount = 0
                width, depth, dim = layerMap.shape
                px = x + 1
                py = y + 1
                while py < y + 1 + size:
                    if px < width - 1 and py < depth - 1:
                        if layerMap[px][py][0] in BADFOUNDATIONBLOCKS:
                            badFoundationCount += 1
                            print "Badfoundations :", badFoundationCount
                            if badFoundationCount > 9:  # is a problem for us
                                print "Badfoundations:", badFoundationCount
                                okToBuild = False  # Can't build on quicksand (or lava and water)
                                py = y + 1 + size  # exit loop
                    px += 1
                    if px >= x + 1 + size:
                        px = x + 1
                        py += 1
                if okToBuild == True:
                    # what is the height to use? Try for average...
                    avgHeight = 0
                    for ppx in xrange(x, x + size):
                        for ppy in xrange(y, y + size):
                            avgHeight += heightMap[ppx][ppy]
                    avgHeight = int(avgHeight / (size * size))
                    print avgHeight
                    plotArea = BoundingBox(
                        (box.minx + x, avgHeight, box.minz + y),
                        (size, box.maxy - (avgHeight),
                         size))  # Save this plot, discard all others
                    plotAreas.append((plotArea, True))
                    print "Viable area", plotArea
                else:
                    print "Bad foundations at", x, y, size

    resultAreas = []
    keepGoing = True
    blueprintCounter = 0
    while keepGoing == True and len(plotAreas) > 0 and blueprintCounter < len(
            chosenVariant):  # Bounds checking
        shuffle(plotAreas)
        (box, availableFlag) = plotAreas.pop()  # Get an area
        if availableFlag == True:
            # Chop up the box to allocate space to the child. We'll use a 2D centre segmentation method
            width, height, depth = getDimensionsFromBox(box)

            size = -1
            if width >= LARGE and height >= LARGE and depth >= LARGE:
                size = LARGE
            elif width >= MEDIUM and height >= MEDIUM and depth >= MEDIUM:
                size = MEDIUM
            elif width >= SMALL and height > SMALL and depth > SMALL:
                size = SMALL
            if size != -1:  # -1 is invalid - selection too small
                # Carve up the area, allocate the central portion to the delegate generator, and return the free ones to the area stack for re-use
                chopXPos1 = ((box.maxx + box.minx) >> 1) - (size >> 1)
                chopXPos2 = ((box.maxx + box.minx) >> 1) + (size >> 1)
                chopZPos1 = ((box.maxz + box.minz) >> 1) - (size >> 1)
                chopZPos2 = ((box.maxz + box.minz) >> 1) + (size >> 1)

                # These are the free areas
                areas.append((BoundingBox(
                    (box.minx, box.miny, box.minz),
                    (chopXPos1 - box.minx, height, chopZPos2 - box.minz)),
                              True))
                areas.append((BoundingBox(
                    (box.minx, box.miny, chopZPos2),
                    (chopXPos2 - box.minx, height, box.maxz - 1 - chopZPos2)),
                              True))
                areas.append((BoundingBox((chopXPos2, box.miny, chopZPos1),
                                          (box.maxx - 1 - chopXPos2, height,
                                           box.maxz - 1 - chopZPos1)), True))
                areas.append((BoundingBox(
                    (chopXPos1, box.miny, box.minz),
                    (box.maxx - 1 - chopXPos1, height, chopZPos1 - box.minz)),
                              True))

                # This is the new building location
                newBox = BoundingBox((0, 0, 0), (size, size, size))

                # Create a new level to generate the building within and, once built, copy it back over onto the level
                # scratchpadHouse = makeBlankAreaOfSizeWHD(size,height,size)

                # Clear out all the nuisance blocks

                AIR = (0, 0)
                for y in xrange(box.miny, box.miny + size):
                    for z in xrange(chopZPos1, chopZPos1 + size):
                        for x in xrange(chopXPos1, chopXPos1 + size):
                            (theBlockID,
                             theBlockData) = getBlock(level, x, y, z)
                            if theBlockID in IGNOREBLOCKIDS:
                                setBlock(level, x, y, z, AIR)

                scratchpadLand = copyAreaOfSizeWHDFromSchematicAtPosXYZ(
                    level, size, height, size, chopXPos1, box.miny, chopZPos1)
                newGeneratedAreas = delegateGeneration(
                    chosenVariant[blueprintCounter], scratchpadLand,
                    [(newBox, True)])
                # scratchpadLand.copyBlocksFrom(scratchpadHouse,BoundingBox((0,0,0),(size,height,size)),(0,0,0))
                pasteAreaOfSizeWHDToSchematicAtPosXYZ(scratchpadLand, level,
                                                      scratchpadLand.Width,
                                                      scratchpadLand.Height,
                                                      scratchpadLand.Length,
                                                      chopXPos1, box.miny,
                                                      chopZPos1)
                # Put in some support pylons if there are parts of the house suspended...
                log("Placing building supports")
                for iz in xrange(chopZPos1, chopZPos1 + scratchpadLand.Length):
                    for ix in xrange(chopXPos1,
                                     chopXPos1 + scratchpadLand.Width):
                        iy = box.miny + scratchpadLand.Height - 1
                        drawPylon = False
                        while (iy >= 0
                               and drawPylon == True) or (drawPylon == False
                                                          and iy >= box.miny):
                            (theBlockID,
                             theBlockData) = getBlock(level, ix, iy, iz)
                            if drawPylon == True and (
                                    theBlockID == 0
                                    or theBlockID in IGNOREBLOCKIDS or
                                    theBlockID in [8, 9, 10, 11]):  # + Liquids
                                setBlock(level, ix, iy, iz,
                                         (4, 0))  # Cobblestone
                            elif theBlockID == 4:
                                drawPylon = True
                            elif drawPylon == True:
                                drawPylon = False  # Turn it off
                                iy = 0  # Break out
                            iy -= 1

                blueprintCounter += 1  # Move onto the next building type
                resultAreas.append((box, True))
            else:
                log("Unable to find space for generation within area " +
                    str(box))
                # Discard this area, it's too small a fragment and cannot be effectively used at this time
                # This causes the areas list to tend to empty
                # TODO: consider putting micro-details into tiny areas

    # Segmentation of the village - low walls and lines of trees/shrubs
    # Voronoi cells
    log("Creating yards and walls")
    minx = 1000000000
    minz = 1000000000
    maxx = -1000000000
    maxz = -1000000000
    points = []

    for (box, flag) in resultAreas:
        box1centrex = (box.maxx + box.minx) >> 1
        box1centrez = (box.maxz + box.minz) >> 1
        points.append((box1centrex, box1centrez))
        if box1centrex < minx: minx = box1centrex
        if box1centrex > maxx: maxx = box1centrex
        if box1centrez < minz: minz = box1centrez
        if box1centrez > maxz: maxz = box1centrez
    log(str(points))
    v = zeros((maxx - minx, maxz - minz, 4))
    for z in xrange(minz, maxz):
        for x in xrange(minx, maxx):
            px = x - minx
            pz = z - minz
            if v[px][pz][3] == 0: v[px][pz][2] = 1000000000
            for X, Z in points:
                dx = x - X
                dz = z - Z
                dist = dx * dx + dz * dz
                if dist < v[px][pz][2]:
                    v[px][pz][0] = X  # Which point we're associated with
                    v[px][pz][1] = Z
                    v[px][pz][2] = dist  # Store a distance
                    v[px][pz][3] = 1  # Mark processed
    print v
    edgePoints = []
    # Find edgePoints - those points which are adjacent to a different zone by (X,Z)
    for z in xrange(0, maxz - minz - 1):
        for x in xrange(0, maxx - minx - 1):
            if v[x][z][3] == 1 and v[x][z + 1][3] == 1 and v[x + 1][z][3] == 1:
                if v[x][z][0] != v[x + 1][z][0] or v[x][z][1] != v[
                        x + 1][z][1] or v[x][z][0] != v[x][
                            z + 1][0] or v[x][z][1] != v[x][z + 1][
                                1]:  # If any of the rightmost/nextmost points are different, this is an edge
                    edgePoints.append((x + minx, z + minz))
    log("Making walls")
    log(str(len(edgePoints)))
    COBBLESTONE = 4
    MOSSCOBBLESTONE = 48
    COBBLESTONEWALL = 139
    TORCH_UP = (50, 5)
    for x, z in edgePoints:
        if randint(1, 10) > 5:
            y = level.Height
            while y >= 0:
                theBlockID, theBlockData = getBlock(level, x, y, z)
                if theBlockID == 2:  # Grass
                    if randint(1, 10) < 0:  # Shrubs and trees DISABLED
                        LEAVES = (18, randint(0, 11))
                        LOG = (17, randint(0, 3))
                        ht = randint(1, 6)
                        for y1 in xrange(y, y + ht):
                            setBlock(level, x, y1, z, LOG)
                            for dx in range(-1, 2):
                                setBlock(level, x + dx, y1, z, LEAVES)
                            for dz in range(-1, 2):
                                setBlock(level, x, y1, dz + dz, LEAVES)
                        for y1 in xrange(y + ht, y + ht + (ht >> 1)):
                            setBlock(level, x, y1, z, LEAVES)
                    else:
                        setBlock(level, x, y, z, (MOSSCOBBLESTONE, 0))
                        if randint(1, 10) > 2:
                            setBlock(level, x, y + 1, z, (COBBLESTONE, 0))
                            if randint(1, 10) > 5:
                                setBlock(level, x, y + 2, z,
                                         (COBBLESTONEWALL, randint(0, 1)))
                                if randint(1, 10) > 8:
                                    setBlock(level, x, y + 3, z, TORCH_UP)
                    y = 0  # Break. Job done
                y -= 1

    # Paths in the grass through resultAreas
    log("Making paths")
    heightW, heightD = heightMap.shape
    PATH = (208, 0)
    pathCount = 20
    while pathCount > 0 and len(resultAreas) > pathCount:
        (box, flag) = resultAreas[randint(0, len(resultAreas) - 1)]
        (box2, flag1) = resultAreas[randint(0, len(resultAreas) - 1)]
        if flag and flag1 and box != box2:
            pathCount -= 1
            log("Pathing... " + str(pathCount))
            box1centrex = (box.maxx + box.minx) >> 1
            box1centrez = (box.maxz + box.minz) >> 1
            box2centrex = (box2.maxx + box2.minx) >> 1
            box2centrez = (box2.maxz + box2.minz) >> 1
            # Calculate the line from box1 to box 2
            P = []
            P.append((box1centrex, 0, box1centrez))
            P.append(P[0])
            P.append(
                (((box1centrex + box2centrex) >> 1) + randint(-100, 100), 0,
                 ((box1centrez + box2centrez) >> 1) + randint(-100, 100)))
            P.append((box2centrex, 0, box2centrez))
            P.append(P[len(P) - 1])
            Q = calcLinesSmooth(4, P)
            for (x, y, z) in Q:
                x = x + randint(-2, 2)
                z = z + randint(-2, 2)
                if randint(1, 10) > 3:
                    y = level.Height
                    while y >= 0:
                        theBlockID, theBlockData = getBlock(level, x, y, z)
                        if theBlockID == 2:  # Grass
                            setBlock(level, x, y, z, PATH)
                            y = 0  # Break. Job done
                        y -= 1
    return resultAreas  # Tell the parent generator what we've done
Example #4
0
def create(generatorName, level, areas):
    '''
		We are passed:
		- a string naming this method as 'generatorName',
		- a pymclevel "level" or MCSchematic object as 'level',
		- and a list of (BoundingBox,flag) tuples as 'areas'
	'''

    log("Generating a " + generatorName)  # Dump a message to the console

    # Some useful material definitions
    AIR = (0, 0)
    STONEBRICKS = (98, 1)
    COBBLESTONE = (4, 0)
    BRICKS = (45, 0)
    WOODPLANKS = (5, 0)
    FLOORHEIGHT = 5

    while len(
            areas
    ) > 0:  # Iterate through the possible build plot areas we were passed.
        (box, availableFlag) = areas.pop()  # Select the first area BoundingBox
        if availableFlag == True:  # Confirm we're allowed to use it
            log("Generating a " + generatorName + " at " +
                str(box))  # Informational to show we found a plot to build in
            width, height, depth = getDimensionsFromBox(
                box)  # Find out how much space we've been given
            if width >= 16 and depth >= 16:  # Minimum viable generation space
                cx = width >> 1  # Pre-calculate the centre via halving through a bit shift
                cz = depth >> 1  # Pre-calculate the centre via halving through a bit shift

                # A tower is a cylinder with a hat on it.
                towerHeight = height  # This is a normal tower with a flat roof
                if randint(1, 10) > 7:
                    towerHeight = int(
                        height / 3 *
                        2)  # Leave 33% room for the roof otherwise

                radius = cx - (cx >> 1)  # Push the tower wall into the box
                r2 = radius * radius  # Square of the radius. We'll use this a little later to work out if we are in or outside the tower wall
                for y in xrange(0, towerHeight):
                    for z in xrange(0, depth):
                        dz = z - cz  # distance to centre on z axis
                        ddz = dz * dz  # pre-calculate the distance squared
                        for x in xrange(0, width):
                            dx = x - cx  # distance to centre on x axis
                            ddx = dx * dx  # pre-calculate the distance squared
                            dist2 = ddx + ddz  # square of the distance. No need to square-root this
                            if dist2 <= r2:  # We're within the tower
                                material = AIR  # Default to overwriting the tower space with air
                                if dist2 > r2 - 16:  # This is the wall thickness
                                    material = STONEBRICKS  # Wall
                                else:  # Inside the wall within a room. Put a floor at this offset
                                    if y % FLOORHEIGHT == 1:
                                        material = WOODPLANKS
                                if y == 0 or (material != AIR and width > 16
                                              and randint(1, 10) == 1):
                                    material = COBBLESTONE  # Bottom layer cobblestone which is allows us to pack in empty space below

                                setBlock(
                                    level, box.minx + x, box.miny + y,
                                    box.minz + z, material
                                )  # Clear the block from this position regardless of what it is
                # Draw the roof, if this tower has one
                for y in xrange(towerHeight, height):
                    scalingRatio = 1.0 - float(y - towerHeight) / float(
                        height - towerHeight
                    )  # this works out how much to taper the radius
                    rad = (cx / 3 * 2) * scalingRatio
                    r2 = int(rad *
                             rad)  # The radius gets smaller the higher we go
                    for z in xrange(0, depth):
                        dz = z - cz  # distance to centre on z axis
                        ddz = dz * dz  # pre-calculate the distance squared
                        for x in xrange(0, width):
                            dx = x - cx  # distance to centre on x axis
                            ddx = dx * dx  # pre-calculate the distance squared
                            dist2 = ddx + ddz  # square of the distance. No need to square-root this
                            if dist2 <= r2:  # We're within the roof
                                material = BRICKS
                                setBlock(level, box.minx + x, box.miny + y,
                                         box.minz + z,
                                         material)  # Draw the roof

                # Window features and doorways
                towerRadius = radius >> 1
                for y in xrange(0, towerHeight):
                    # Randomly punch windows through
                    if y % FLOORHEIGHT == 3 or y == 2:  # y == 2 for ground floor access
                        for x in xrange(cx - towerRadius + 1,
                                        cx + towerRadius):
                            if x != cx:
                                if randint(1, 10) == 1:
                                    hitWall = False
                                    for z in xrange(0, depth):  # Drill through
                                        theBlock = getBlock(
                                            level, box.minx + x, box.miny + y,
                                            box.minz + z)
                                        if theBlock != AIR and hitWall == False:
                                            hitWall = False
                                            setBlock(level, box.minx + x,
                                                     box.miny + y,
                                                     box.minz + z, AIR)
                                            setBlock(level, box.minx + x,
                                                     box.miny + y + 1,
                                                     box.minz + z, AIR)
                                            z = depth

                        for z in xrange(cz - towerRadius + 1,
                                        cz + towerRadius):
                            if z != cz:
                                if randint(1, 10) == 1:
                                    hitWall = False
                                    for x in xrange(0, width):  # Drill through
                                        theBlock = getBlock(
                                            level, box.minx + x, box.miny + y,
                                            box.minz + z)
                                        if theBlock != AIR and hitWall == False:
                                            hitWall = False
                                            setBlock(level, box.minx + x,
                                                     box.miny + y,
                                                     box.minz + z, AIR)
                                            setBlock(level, box.minx + x,
                                                     box.miny + y + 1,
                                                     box.minz + z, AIR)
                                            x = width
Example #5
0
    def add(self, room):  # This is an efficient packing problem
        # Try to place the new room in the floorplan
        # Rooms can overlap by one block for a shared wall
        # For this method we don't care much if there's a gap between rooms. Consider fixing this by growing a blobby room plan later.
        width, height, depth = self.size
        roomWidth, roomHeight, roomDepth = room.size

        # precheck - can it fit the available dimensions?

        widthGap = width - roomWidth - 2
        heightGap = height - roomHeight
        depthGap = depth - roomDepth - 2
        if widthGap < 1 or heightGap < 0 or depthGap < 1:
            return False  # I cannot place this room in this plan because it is too big

        # Ok, now we can check if there's a spot to place the new room. Don't be too aggressive. We want interesting, not optimal
        attempts = 100
        while attempts >= 0:
            attempts -= 1
            xpos = randint(1, widthGap)
            zpos = randint(1, depthGap)

            collides = False
            i = 0
            while i < len(self.rooms):
                eachRoom = self.rooms[i]
                x, y, z = eachRoom.pos
                dx, dy, dz = eachRoom.size
                # Remember a 1 block overlap is legal when placing rooms so the adjustment is made to the calculation below
                if checkBoundingBoxIntersect(
                    (xpos + 1, zpos + 1, xpos + roomWidth - 2,
                     zpos + roomDepth - 2),
                    (x, z, x + dx, z + dz)) == True:  # Fail - overlap
                    collides = True
                    i = len(self.rooms)  # Found an exception, stop looping
                i += 1

            if collides == False:  # We didn't hit anything so we can use this position
                room.pos = (
                    xpos, 0, zpos
                )  # Base condition - just put it where it doesn't collide
                log("Trying to shuffle the room " + str(room.pos) + " " +
                    str(room.size))
                # Now shuffle it into the centre until it collides with another room so it is adjacent to an existing room
                cx = width >> 1  # Centre x
                cz = depth >> 1  # Centre z

                keepGoing = True
                newPosx = xpos
                newPosz = zpos

                dx = newPosx - cx  # Distance to centre
                dz = newPosz - cz  # Distance to centre
                dirx = 0
                dirz = 0
                if dx < 0:
                    dirx = 1
                if dx > 0:
                    dirx = -1
                if dz < 0:
                    dirz = 1
                if dz > 0:
                    dirz = -1
                if dirz != 0 or dirx != 0:  # We have some wiggle room
                    counter = 100
                    while keepGoing and counter > 0:
                        counter -= 1
                        newPosx -= dirx
                        newPosz -= dirz
                        if newPosx > 1 and newPosz > 1 and newPosx + roomWidth < width and newPosz + roomDepth < depth:
                            while i < len(self.rooms):
                                eachRoom = self.rooms[i]
                                x, y, z = eachRoom.pos
                                dx, dy, dz = eachRoom.size
                                if checkBoundingBoxIntersect(
                                    (newPosx + 1, newPosz + 1, newPosx +
                                     roomWidth - 1, newPosz + roomDepth - 1),
                                    (x, z, x + dx, z + dz)) == True:  # Overlap
                                    # Smash!
                                    keepGoing = False
                                    i = len(self.rooms)
                                    room.pos = (newPosx, 0, newPosz)
                        else:
                            keepGoing = False  # Could collide anywhere. Just put it where we first wanted to.
                self.rooms.append(room)

                attempts = -1  # Break out of the loop
                return True  # Successful addition
        return False  # We couldn't find a place to pop this room
Example #6
0
    def furnish(self, level):
        # Based on the type of room, place things around.
        log("Furnishing...")
        AIR = (0, 0)
        DOORS = [64]
        (ox, oy, oz) = self.pos
        width, height, depth = self.size
        colortheme = randint(0, 15)
        if self.type == "Bedroom":
            # Place a bed

            # Bed. Location shouldn't be adjacent to a door. Find a spot with the head to a wall. Fair share of orientations
            BEDFOOTNORTH = (26, 0)
            BEDFOOTEAST = (26, 1)
            BEDFOOTSOUTH = (26, 2)
            BEDFOOTWEST = (26, 3)
            BEDHEADNORTH = (26, 8)
            BEDHEADEAST = (26, 9)
            BEDHEADSOUTH = (26, 10)
            BEDHEADWEST = (26, 11)

            # Walk the floor looking for a safe place to put a bed
            y = oy + 1
            attempts = 100
            while attempts > 0:
                attempts -= 1
                x = randint(ox + 1, ox + width - 1)
                z = randint(oz + 1, oz + depth - 1)
                thisSpot = getBlock(level, x, y, z)
                if thisSpot == AIR:
                    wid, wdata = westSpot = getBlock(level, x - 1, y, z)
                    eid, edata = eastSpot = getBlock(level, x + 1, y, z)
                    sid, sdata = southSpot = getBlock(level, x, y, z + 1)
                    nid, ndata = northSpot = getBlock(level, x, y, z - 1)
                    if westSpot != AIR and eastSpot == AIR and wid not in DOORS and nid not in DOORS and sid not in DOORS:
                        eid, edata = eastSpot = getBlock(level, x + 2, y, z)
                        sid, sdata = southSpot = getBlock(
                            level, x + 1, y, z + 1)
                        nid, ndata = northSpot = getBlock(
                            level, x + 1, y, z - 1)
                        if eid not in DOORS and sid not in DOORS and nid not in DOORS:
                            setBlock(level, x, y, z, BEDHEADEAST)
                            setBlock(level, x + 1, y, z, BEDFOOTEAST)
                            attempts = 0

                    elif eastSpot != AIR and westSpot == AIR and eid not in DOORS and nid not in DOORS and sid not in DOORS:
                        wid, edata = westSpot = getBlock(level, x - 2, y, z)
                        sid, sdata = southSpot = getBlock(
                            level, x - 1, y, z + 1)
                        nid, ndata = northSpot = getBlock(
                            level, x - 1, y, z - 1)
                        if wid not in DOORS and sid not in DOORS and nid not in DOORS:
                            setBlock(level, x, y, z, BEDHEADWEST)
                            setBlock(level, x - 1, y, z, BEDFOOTWEST)
                            attempts = 0

                    elif northSpot != AIR and southSpot == AIR and eid not in DOORS and wid not in DOORS and nid not in DOORS:
                        wid, edata = westSpot = getBlock(
                            level, x - 1, y, z + 1)
                        eid, sdata = southSpot = getBlock(
                            level, x + 1, y, z + 1)
                        sid, ndata = northSpot = getBlock(level, x, y, z + 2)
                        if wid not in DOORS and sid not in DOORS and eid not in DOORS:
                            setBlock(level, x, y, z, BEDHEADSOUTH)
                            setBlock(level, x, y, z + 1, BEDFOOTSOUTH)
                            attempts = 0

                    elif northSpot == AIR and southSpot != AIR and eid not in DOORS and wid not in DOORS and sid not in DOORS:
                        wid, edata = westSpot = getBlock(
                            level, x - 1, y, z - 1)
                        eid, sdata = southSpot = getBlock(
                            level, x + 1, y, z - 1)
                        nid, ndata = northSpot = getBlock(level, x, y, z - 2)
                        if wid not in DOORS and eid not in DOORS and nid not in DOORS:
                            setBlock(level, x, y, z, BEDHEADNORTH)
                            setBlock(level, x, y, z - 1, BEDFOOTNORTH)
                            attempts = 0

        if self.type == "LivingRoom":
            STAIRCHAIR = 53  # 0,1,2,3
            log("Chairs")
            placements = []
            for i in xrange(0, randint(2, 8)):
                placements.append(STAIRCHAIR)
            y = oy + 1
            attempts = 100
            while attempts > 0 and len(placements) > 0:
                attempts -= 1
                x = randint(ox + 1, ox + width - 1)
                z = randint(oz + 1, oz + depth - 1)
                thisSpot = getBlock(level, x, y, z)
                if thisSpot == AIR:
                    wid, wdata = westSpot = getBlock(level, x - 1, y, z)
                    eid, edata = eastSpot = getBlock(level, x + 1, y, z)
                    sid, sdata = southSpot = getBlock(level, x, y, z + 1)
                    nid, ndata = northSpot = getBlock(level, x, y, z - 1)
                    if westSpot == AIR and eastSpot == AIR and southSpot == AIR and northSpot == AIR:
                        block = placements.pop()
                        setBlock(level, x, y, z, (block, randint(0, 3)))

        if self.type == "Kitchen":
            CRAFTINGTABLE = 58
            FURNACE = 61  # 2,3,4,5
            CAULDRON = 118  # 0,1,2,3
            log("Kitchen")
            placements = [CAULDRON, FURNACE, CRAFTINGTABLE]

            # Walk the floor looking for a safe place to put a crafting table
            y = oy + 1
            attempts = 100
            while attempts > 0 and len(placements) > 0:
                attempts -= 1
                x = randint(ox + 1, ox + width - 1)
                z = randint(oz + 1, oz + depth - 1)
                thisSpot = getBlock(level, x, y, z)
                if thisSpot == AIR:
                    wid, wdata = westSpot = getBlock(level, x - 1, y, z)
                    eid, edata = eastSpot = getBlock(level, x + 1, y, z)
                    sid, sdata = southSpot = getBlock(level, x, y, z + 1)
                    nid, ndata = northSpot = getBlock(level, x, y, z - 1)
                    if westSpot != AIR and eastSpot == AIR and wid not in DOORS and nid not in DOORS and sid not in DOORS:
                        block = placements.pop()
                        blockID = 0
                        if block == CAULDRON:
                            blockID = randint(0, 3)
                        elif block == FURNACE:
                            blockID = 4
                        setBlock(level, x, y, z, (block, blockID))

                    elif eastSpot != AIR and westSpot == AIR and eid not in DOORS and nid not in DOORS and sid not in DOORS:
                        block = placements.pop()
                        blockID = 0
                        if block == CAULDRON:
                            blockID = randint(0, 3)
                        elif block == FURNACE:
                            blockID = 5
                        setBlock(level, x, y, z, (block, blockID))

                    elif northSpot != AIR and southSpot == AIR and eid not in DOORS and wid not in DOORS and nid not in DOORS:
                        block = placements.pop()
                        blockID = 0
                        if block == CAULDRON:
                            blockID = randint(0, 3)
                        elif block == FURNACE:
                            blockID = 3
                        setBlock(level, x, y, z, (block, blockID))

                    elif northSpot == AIR and southSpot != AIR and eid not in DOORS and wid not in DOORS and sid not in DOORS:
                        block = placements.pop()
                        blockID = 0
                        if block == CAULDRON:
                            blockID = randint(0, 3)
                        elif block == FURNACE:
                            blockID = 2
                        setBlock(level, x, y, z, (block, blockID))

        # All rooms - table and torch
        log("Chest")
        CHEST = 54
        y = oy + 1
        attempts = 100
        while attempts > 0:
            attempts -= 1
            x = randint(ox + 1, ox + width - 1)
            z = randint(oz + 1, oz + depth - 1)
            thisSpot = getBlock(level, x, y, z)
            if thisSpot == AIR:
                wid, wdata = westSpot = getBlock(level, x - 1, y, z)
                eid, edata = eastSpot = getBlock(level, x + 1, y, z)
                sid, sdata = southSpot = getBlock(level, x, y, z + 1)
                nid, ndata = northSpot = getBlock(level, x, y, z - 1)
                if westSpot == AIR and eastSpot == AIR and southSpot == AIR and northSpot == AIR:
                    setBlock(level, x, y, z, (CHEST, randint(2, 5)))
                    attempts = 0
        log("Light")
        TORCH_UP = (50, 5)
        #TABLE = (85,0) # Fence
        y = oy + 1
        attempts = 100
        while attempts > 0:
            attempts -= 1
            x = randint(ox + 1, ox + width - 1)
            z = randint(oz + 1, oz + depth - 1)
            thisSpot = getBlock(level, x, y, z)
            if thisSpot == AIR:
                wid, wdata = westSpot = getBlock(level, x - 1, y, z)
                eid, edata = eastSpot = getBlock(level, x + 1, y, z)
                sid, sdata = southSpot = getBlock(level, x, y, z + 1)
                nid, ndata = northSpot = getBlock(level, x, y, z - 1)
                if westSpot == AIR and eastSpot == AIR and southSpot == AIR and northSpot == AIR:
                    setBlock(level, x, y, z, (35, colortheme))
                    setBlock(level, x, y + 1, z, TORCH_UP)
                    attempts = 0

        log("Carpet")
        # All rooms - Carpet
        CARPET = 171
        if randint(1, 10) < 10:  # Add carpet
            log("Adding carpet")
            offset = randint(1, 3)
            fill(level, (ox + offset, oy + 1, oz + offset),
                 (ox + width - offset, oy + 2, oz + depth - offset),
                 (CARPET, colortheme))