Package me.daddychurchill.CityWorld.Plats

Source Code of me.daddychurchill.CityWorld.Plats.BuildingLot

package me.daddychurchill.CityWorld.Plats;

import me.daddychurchill.CityWorld.WorldGenerator;
import me.daddychurchill.CityWorld.Context.DataContext;
import me.daddychurchill.CityWorld.Factories.CurvedWallFactory;
import me.daddychurchill.CityWorld.Factories.InteriorWallFactory;
import me.daddychurchill.CityWorld.Factories.MaterialFactory;
import me.daddychurchill.CityWorld.Factories.OutsideNSWallFactory;
import me.daddychurchill.CityWorld.Factories.OutsideWEWallFactory;
import me.daddychurchill.CityWorld.Plugins.RoomProvider;
import me.daddychurchill.CityWorld.Rooms.Populators.EmptyWithNothing;
import me.daddychurchill.CityWorld.Support.ByteChunk;
import me.daddychurchill.CityWorld.Support.Direction;
import me.daddychurchill.CityWorld.Support.Direction.Facing;
import me.daddychurchill.CityWorld.Support.Direction.Stair;
import me.daddychurchill.CityWorld.Support.Direction.StairWell;
import me.daddychurchill.CityWorld.Support.Direction.TrapDoor;
import me.daddychurchill.CityWorld.Support.BlackMagic;
import me.daddychurchill.CityWorld.Support.Odds;
import me.daddychurchill.CityWorld.Support.PlatMap;
import me.daddychurchill.CityWorld.Support.RealChunk;
import me.daddychurchill.CityWorld.Support.SupportChunk;
import me.daddychurchill.CityWorld.Support.SurroundingFloors;
import me.daddychurchill.CityWorld.Support.Direction.Door;
import me.daddychurchill.CityWorld.Support.Surroundings;

import org.bukkit.Material;

public abstract class BuildingLot extends ConnectedLot {
 
  private static RoomProvider contentsNothing = new EmptyWithNothing();
 
  protected boolean neighborsHaveIdenticalHeights;
  protected double neighborsHaveSimilarHeightsOdds;
  protected double neighborsHaveSimilarRoundedOdds;
  protected int height; // floors up
  protected int depth; // floors down
  protected boolean needStairsUp;
  protected boolean needStairsDown;
  protected boolean rounded; // rounded corners if possible? (only if the insets match)
  protected MaterialFactory wallsWE;
  protected MaterialFactory wallsNS;
  protected MaterialFactory wallsInterior;
  protected MaterialFactory wallsCurved;
  protected int aboveFloorHeight;
  protected int basementFloorHeight;
 
  protected final static Material antennaBase = Material.CLAY;
  protected final static Material antenna = Material.FENCE;
  protected final static Material conditioner = Material.DOUBLE_STEP;
  protected final static Material conditionerTrim = Material.STONE_PLATE;
  protected final static Material conditionerGrill = Material.RAILS;
  protected final static Material duct = Material.STEP;
  protected final static Material tileMaterial = Material.STEP;
 
  public enum RoofStyle {FLATTOP, EDGED, PEAK, TENT_NORTHSOUTH, TENT_WESTEAST};//, SLANT_NORTH, SLANT_SOUTH, SLANT_WEST, SLANT_EAST};
  public enum RoofFeature {ANTENNAS, CONDITIONERS, TILE};
  protected RoofStyle roofStyle;
  protected RoofFeature roofFeature;
  protected int roofScale;
 
  public enum StairStyle {STUDIO_A, CROSSED, LANDING, CORNER};
  protected StairStyle stairStyle;
  protected Direction.Facing stairDirection;
 
  public enum InteriorStyle {COLUMNS_ONLY, WALLS_ONLY, COLUMNS_OFFICES, WALLS_OFFICES, RANDOM};
  protected InteriorStyle interiorStyle;
  protected double oddsOfAnInteriorDoor = Odds.oddsExtremelyLikely;
  protected double oddsOfAnExteriorDoor = Odds.oddsSomewhatLikely;
  protected Material columnMaterial;
  protected boolean forceNarrowInteriorMode = false;
  protected double differentInteriorModes = Odds.oddsUnlikely;
 
  protected int navLightX = 0;
  protected int navLightY = 0;
  protected int navLightZ = 0;
 
  private final static Material fenceMaterial = Material.IRON_FENCE;
  private final static int fenceHeight = 3;
 
  public RoomProvider roomProviderForFloor(WorldGenerator generator, SupportChunk chunk, int floor, int floorY) {
    return contentsNothing;
  }
 
  public BuildingLot(PlatMap platmap, int chunkX, int chunkZ) {
    super(platmap, chunkX, chunkZ);
    style = LotStyle.STRUCTURE;
   
    DataContext context = platmap.context;
   
    neighborsHaveIdenticalHeights = chunkOdds.playOdds(context.oddsOfIdenticalBuildingHeights);
    neighborsHaveSimilarHeightsOdds = context.oddsOfSimilarBuildingHeights;
    neighborsHaveSimilarRoundedOdds = context.oddsOfSimilarBuildingRounding;
    aboveFloorHeight = DataContext.FloorHeight;
    basementFloorHeight = DataContext.FloorHeight;
    height = 1 + chunkOdds.getRandomInt(context.maximumFloorsAbove);
    depth = 0;
    if (platmap.generator.settings.includeBasements)
      depth = 1 + chunkOdds.getRandomInt(context.maximumFloorsBelow);
    needStairsDown = true;
    needStairsUp = true;
    rounded = chunkOdds.playOdds(context.oddsOfRoundedBuilding);
    roofStyle = pickRoofStyle();
    roofFeature = pickRoofFeature();
    roofScale = 1 + chunkOdds.getRandomInt(2);
    stairStyle = pickStairStyle();
    stairDirection = pickStairDirection();
    interiorStyle = pickInteriorStyle();
    columnMaterial = Material.COBBLE_WALL;
    wallsWE = new OutsideWEWallFactory(chunkOdds, platmap.generator.settings.includeDecayedBuildings);
    wallsNS = new OutsideNSWallFactory(wallsWE);
    wallsCurved = new CurvedWallFactory(wallsWE);
    wallsInterior = new InteriorWallFactory(chunkOdds, platmap.generator.settings.includeDecayedBuildings);
    forceNarrowInteriorMode = chunkOdds.playOdds(context.oddsOfForcedNarrowInteriorMode);
    differentInteriorModes = context.oddsOfDifferentInteriorModes;
  }

  @Override
  public boolean isValidStrataY(WorldGenerator generator, int blockX, int blockY, int blockZ) {
    return blockY < generator.streetLevel - basementFloorHeight * depth;
  }

  @Override
  protected boolean isShaftableLevel(WorldGenerator generator, int blockY) {
    return blockY >= 0 && blockY < generator.streetLevel - basementFloorHeight * depth - 2 - 16
  }

  protected RoofStyle pickRoofStyle() {
    switch (chunkOdds.getRandomInt(5)) {
    case 1:
      return RoofStyle.EDGED;
    case 2:
      return RoofStyle.PEAK;
    case 3:
      return RoofStyle.TENT_NORTHSOUTH;
    case 4:
      return RoofStyle.TENT_WESTEAST;
    default:
      return RoofStyle.FLATTOP;
    }
  }
 
  protected RoofFeature pickRoofFeature() {
    switch (chunkOdds.getRandomInt(3)) {
    case 1:
      return RoofFeature.ANTENNAS;
    case 2:
      return RoofFeature.CONDITIONERS;
    default:
      return RoofFeature.TILE;
    }
  }
 
  protected Material pickGlassMaterial() {
    switch (chunkOdds.getRandomInt(2)) {
    case 1:
      return Material.THIN_GLASS;
    default:
      return Material.GLASS;
    }
  }
 
  protected Facing pickStairDirection() {
    switch (chunkOdds.getRandomInt(4)) {
    case 1:
      return Direction.Facing.NORTH;
    case 2:
      return Direction.Facing.SOUTH;
    case 3:
      return Direction.Facing.WEST;
    default:
      return Direction.Facing.EAST;
    }
  }

  protected StairStyle pickStairStyle() {
    switch (chunkOdds.getRandomInt(4)) {
    case 1:
      return StairStyle.CORNER;
    case 2:
      return StairStyle.CROSSED;
    case 3:
      return StairStyle.STUDIO_A;
    default:
      return StairStyle.LANDING;
    }
  }

  protected InteriorStyle pickInteriorStyle() {
    switch (chunkOdds.getRandomInt(10)) {
    case 1:
      return InteriorStyle.RANDOM;
    case 2:
      return InteriorStyle.WALLS_ONLY;
    case 3:
      return InteriorStyle.COLUMNS_ONLY;
    case 4:
    case 5:
      return InteriorStyle.COLUMNS_OFFICES;
    case 6:
    case 7:
    case 8:
    case 9:
    default:
      return InteriorStyle.WALLS_OFFICES;
    }
  }
 
  // descendants can override this to do something special
  protected InteriorStyle getFloorsInteriorStyle(int floor) {
    return interiorStyle;
  }

  @Override
  public boolean makeConnected(PlatLot relative) {
    boolean result = super.makeConnected(relative);
   
    // other bits
    if (result && relative instanceof BuildingLot) {
      BuildingLot relativebuilding = (BuildingLot) relative;

      neighborsHaveIdenticalHeights = relativebuilding.neighborsHaveIdenticalHeights;
      if (neighborsHaveIdenticalHeights || chunkOdds.playOdds(neighborsHaveSimilarHeightsOdds)) {
        height = relativebuilding.height;
        depth = relativebuilding.depth;
      }
     
      if (chunkOdds.playOdds(neighborsHaveSimilarRoundedOdds))
        rounded = relativebuilding.rounded;
     
      // any other bits
      roofStyle = relativebuilding.roofStyle;
      roofFeature = relativebuilding.roofFeature;
      roofScale = relativebuilding.roofScale;
//      stairStyle = relativebuilding.stairStyle; // commented out because different parts of the building can have different stair styles
      interiorStyle = relativebuilding.interiorStyle;
      columnMaterial = relativebuilding.columnMaterial;
      wallsWE = relativebuilding.wallsWE;
      wallsNS = relativebuilding.wallsNS;
      wallsCurved = relativebuilding.wallsCurved;
      wallsInterior = relativebuilding.wallsInterior;
      if (!chunkOdds.playOdds(differentInteriorModes))
        forceNarrowInteriorMode = relativebuilding.forceNarrowInteriorMode;
     
      // do we need stairs?
      relativebuilding.needStairsDown = relativebuilding.depth > depth;
      relativebuilding.needStairsUp = relativebuilding.height > height;
    }
    return result;
  }
 
  protected SurroundingFloors getNeighboringFloorCounts(PlatMap platmap, int platX, int platZ) {
    SurroundingFloors neighborBuildings = new SurroundingFloors();
   
    // get a list of qualified neighbors
    PlatLot[][] neighborChunks = getNeighborPlatLots(platmap, platX, platZ, true);
    for (int x = 0; x < 3; x++) {
      for (int z = 0; z < 3; z++) {
        if (neighborChunks[x][z] == null) {
          neighborBuildings.floors[x][z] = 0;
        } else {
         
          // in order for this building to be connected to our building they would have to be the same type
          neighborBuildings.floors[x][z] = ((BuildingLot) neighborChunks[x][z]).height;
        }
      }
    }
    neighborBuildings.update();
   
    return neighborBuildings;
  }
 
  protected SurroundingFloors getNeighboringBasementCounts(PlatMap platmap, int platX, int platZ) {
    SurroundingFloors neighborBuildings = new SurroundingFloors();
   
    // get a list of qualified neighbors
    PlatLot[][] neighborChunks = getNeighborPlatLots(platmap, platX, platZ, true);
    for (int x = 0; x < 3; x++) {
      for (int z = 0; z < 3; z++) {
        if (neighborChunks[x][z] == null) {
          neighborBuildings.floors[x][z] = 0;
        } else {
         
          // in order for this building to be connected to our building they would have to be the same type
          neighborBuildings.floors[x][z] = ((BuildingLot) neighborChunks[x][z]).depth;
        }
      }
    }
    neighborBuildings.update();
   
    return neighborBuildings;
  }
 
  protected void drawCeilings(WorldGenerator generator, ByteChunk byteChunk, DataContext context, int y1,
      int height, int insetNS, int insetWE,
      boolean allowRounded, Material ceilingMaterial, Surroundings heights) {
   
    // precalculate
    Material emptyMaterial = getAirMaterial(generator, y1);
    int y2 = y1 + height;
    boolean stillNeedCeiling = true;
    int inset = Math.max(insetNS, insetWE);
   
    // rounded and square inset and there are exactly two neighbors?
    if (allowRounded) {// && rounded) { // already know that... && insetNS == insetWE && heights.getNeighborCount() == 2
      int innerCorner = (byteChunk.width - inset * 2) + inset;
      if (heights.toNorth()) {
        if (heights.toEast()) {
          byteChunk.setArcNorthEast(inset, y1, y2, ceilingMaterial, true);
          if (!heights.toNorthEast())
            byteChunk.setArcNorthEast(innerCorner, y1, y2, emptyMaterial, true);
          stillNeedCeiling = false;
        } else if (heights.toWest()) {
          byteChunk.setArcNorthWest(inset, y1, y2, ceilingMaterial, true);
          if (!heights.toNorthWest())
            byteChunk.setArcNorthWest(innerCorner, y1, y2, emptyMaterial, true);
          stillNeedCeiling = false;
        }
      } else if (heights.toSouth()) {
        if (heights.toEast()) {
          byteChunk.setArcSouthEast(inset, y1, y2, ceilingMaterial, true);
          if (!heights.toSouthEast())
            byteChunk.setArcSouthEast(innerCorner, y1, y2, emptyMaterial, true);
          stillNeedCeiling = false;
        } else if (heights.toWest()) {
          byteChunk.setArcSouthWest(inset, y1, y2, ceilingMaterial, true);
          if (!heights.toSouthWest())
            byteChunk.setArcSouthWest(innerCorner, y1, y2, emptyMaterial, true);
          stillNeedCeiling = false;
        }
      }
    }
   
    // still need to do something?
    if (stillNeedCeiling) {

      // center part
      byteChunk.setBlocks(insetWE, byteChunk.width - insetWE, y1, y2, insetNS, byteChunk.width - insetNS, ceilingMaterial);
     
    }
   
    // only if we are inset
    if (insetWE > 0 || insetNS > 0) {
     
      // cardinal bits
      if (heights.toWest())
        byteChunk.setBlocks(0, insetWE, y1, y2, insetNS, byteChunk.width - insetNS, ceilingMaterial);
      if (heights.toEast())
        byteChunk.setBlocks(byteChunk.width - insetWE, byteChunk.width, y1, y2, insetNS, byteChunk.width - insetNS, ceilingMaterial);
      if (heights.toNorth())
        byteChunk.setBlocks(insetWE, byteChunk.width - insetWE, y1, y2, 0, insetNS, ceilingMaterial);
      if (heights.toSouth())
        byteChunk.setBlocks(insetWE, byteChunk.width - insetWE, y1, y2, byteChunk.width - insetNS, byteChunk.width, ceilingMaterial);

      // corner bits
      if (heights.toNorthWest())
        byteChunk.setBlocks(0, insetWE, y1, y2, 0, insetNS, ceilingMaterial);
      if (heights.toSouthWest())
        byteChunk.setBlocks(0, insetWE, y1, y2, byteChunk.width - insetNS, byteChunk.width, ceilingMaterial);
      if (heights.toNorthEast())
        byteChunk.setBlocks(byteChunk.width - insetWE, byteChunk.width, y1, y2, 0, insetNS, ceilingMaterial);
      if (heights.toSouthEast())
        byteChunk.setBlocks(byteChunk.width - insetWE, byteChunk.width, y1, y2, byteChunk.width - insetNS, byteChunk.width, ceilingMaterial);
    }
  }
 
  protected void drawExteriorParts(WorldGenerator generator, ByteChunk byteChunk, DataContext context, int y1,
      int height, int insetNS, int insetWE,
      boolean allowRounded, Material wallMaterial, Material glassMaterial, Surroundings heights) {
   
    // precalculate
    int y2 = y1 + height;
    boolean stillNeedWalls = true;
    int inset = Math.max(insetNS, insetWE);
   
    // rounded and square inset and there are exactly two neighbors?
    if (allowRounded) {// && rounded) {
     
      // hack the glass material if needed
      if (glassMaterial == Material.THIN_GLASS)
        glassMaterial = Material.GLASS;
     
      // do the sides
      if (heights.toSouth()) {
        if (heights.toWest()) {
          byteChunk.setArcSouthWest(inset, y1, y2, wallMaterial, glassMaterial, wallsCurved);
          if (!heights.toSouthWest()) {
            byteChunk.setBlocks(insetWE, y1, y2, byteChunk.width - insetNS - 1, wallMaterial, glassMaterial, wallsCurved);
          }
          stillNeedWalls = false;
        } else if (heights.toEast()) {
          byteChunk.setArcSouthEast(inset, y1, y2, wallMaterial, glassMaterial, wallsCurved);
          if (!heights.toSouthEast()) {
            byteChunk.setBlocks(byteChunk.width - insetWE - 1, y1, y2, byteChunk.width - insetNS - 1, wallMaterial, glassMaterial, wallsCurved);
          }
          stillNeedWalls = false;
        }
      } else if (heights.toNorth()) {
        if (heights.toWest()) {
          byteChunk.setArcNorthWest(inset, y1, y2, wallMaterial, glassMaterial, wallsCurved);
          if (!heights.toNorthWest()) {
            byteChunk.setBlocks(insetWE, y1, y2, insetNS, wallMaterial, glassMaterial, wallsCurved);
          }
          stillNeedWalls = false;
        } else if (heights.toEast()) {
          byteChunk.setArcNorthEast(inset, y1, y2, wallMaterial, glassMaterial, wallsCurved);
          if (!heights.toNorthEast()) {
            byteChunk.setBlocks(byteChunk.width - insetWE - 1, y1, y2, insetNS, wallMaterial, glassMaterial, wallsCurved);
          }
          stillNeedWalls = false;
        }
      }
    }
   
    // still need to do something?
    if (stillNeedWalls) {
     
      // corner columns
      if (!heights.toNorthWest())
        byteChunk.setBlocks(insetWE, y1, y2, insetNS, wallMaterial);
      if (!heights.toSouthWest())
        byteChunk.setBlocks(insetWE, y1, y2, byteChunk.width - insetNS - 1, wallMaterial);
      if (!heights.toNorthEast())
        byteChunk.setBlocks(byteChunk.width - insetWE - 1, y1, y2, insetNS, wallMaterial);
      if (!heights.toSouthEast())
        byteChunk.setBlocks(byteChunk.width - insetWE - 1, y1, y2, byteChunk.width - insetNS - 1, wallMaterial);
     
      // cardinal walls
      if (!heights.toWest())
        byteChunk.setBlocks(insetWE,  insetWE + 1, y1, y2, insetNS + 1, byteChunk.width - insetNS - 1, wallMaterial, glassMaterial, wallsNS);
      if (!heights.toEast())
        byteChunk.setBlocks(byteChunk.width - insetWE - 1,  byteChunk.width - insetWE, y1, y2, insetNS + 1, byteChunk.width - insetNS - 1, wallMaterial, glassMaterial, wallsNS);
      if (!heights.toNorth())
        byteChunk.setBlocks(insetWE + 1, byteChunk.width - insetWE - 1, y1, y2, insetNS, insetNS + 1, wallMaterial, glassMaterial, wallsWE);
      if (!heights.toSouth())
        byteChunk.setBlocks(insetWE + 1, byteChunk.width - insetWE - 1, y1, y2, byteChunk.width - insetNS - 1, byteChunk.width - insetNS, wallMaterial, glassMaterial, wallsWE);
     
    }
     
    // only if there are insets
    if (insetWE > 0) {
      if (heights.toWest()) {
        if (!heights.toNorthWest())
          byteChunk.setBlocks(0, insetWE, y1, y2, insetNS, insetNS + 1, wallMaterial, glassMaterial, wallsWE);
        if (!heights.toSouthWest())
          byteChunk.setBlocks(0, insetWE, y1, y2, byteChunk.width - insetNS - 1, byteChunk.width - insetNS, wallMaterial, glassMaterial, wallsWE);
      }
      if (heights.toEast()) {
        if (!heights.toNorthEast())
          byteChunk.setBlocks(byteChunk.width - insetWE, byteChunk.width, y1, y2, insetNS, insetNS + 1, wallMaterial, glassMaterial, wallsWE);
        if (!heights.toSouthEast())
          byteChunk.setBlocks(byteChunk.width - insetWE, byteChunk.width, y1, y2, byteChunk.width - insetNS - 1, byteChunk.width - insetNS, wallMaterial, glassMaterial, wallsWE);
      }
    }
    if (insetNS > 0) {
      if (heights.toNorth()) {
        if (!heights.toNorthWest())
          byteChunk.setBlocks(insetWE, insetWE + 1, y1, y2, 0, insetNS, wallMaterial, glassMaterial, wallsNS);
        if (!heights.toNorthEast())
          byteChunk.setBlocks(byteChunk.width - insetWE - 1, byteChunk.width - insetWE, y1, y2, 0, insetNS, wallMaterial, glassMaterial, wallsNS);
      }
      if (heights.toSouth()) {
        if (!heights.toSouthWest())
          byteChunk.setBlocks(insetWE, insetWE + 1, y1, y2, byteChunk.width - insetNS, byteChunk.width, wallMaterial, glassMaterial, wallsNS);
        if (!heights.toSouthEast())
          byteChunk.setBlocks(byteChunk.width - insetWE - 1, byteChunk.width - insetWE, y1, y2, byteChunk.width - insetNS, byteChunk.width, wallMaterial, glassMaterial, wallsNS);
      }
    }
  }
 
  protected void drawInteriorParts(WorldGenerator generator, RealChunk chunk,
      DataContext context, RoomProvider rooms,
      int floor, int floorAt, int floorHeight,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairLocation,
      Material materialStair, Material materialStairWall, Material materialPlatform,
      boolean drawStairWall, boolean drawStairs,
      boolean topFloor, boolean singleFloor,
      Surroundings heights) {
   
    drawInteriorParts(generator, chunk, context, getFloorsInteriorStyle(floor),
        rooms, floor, floorAt, floorHeight, insetNS, insetWE,
        allowRounded, materialWall, materialGlass, stairLocation,
        materialStair, materialStairWall, materialPlatform,
        drawStairWall, drawStairs, topFloor, singleFloor,
        heights);
  }
 
  private void drawInteriorParts(WorldGenerator generator, RealChunk chunk,
      DataContext context, InteriorStyle style, RoomProvider rooms,
      int floor, int floorAt, int floorHeight,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairLocation,
      Material materialStair, Material materialStairWall, Material materialPlatform,
      boolean drawStairWall, boolean drawStairs,
      boolean topFloor, boolean singleFloor,
      Surroundings heights) {
   
    // need to do more stuff?
    boolean drawInteriorDoors = false;
    boolean drawExteriorDoors = floor == 0;
    boolean drawNarrowInteriors = forceNarrowInteriorMode ||
                    (!heights.toNorthWest() &&
                     !heights.toNorthEast() &&
                     !heights.toSouthWest() &&
                     !heights.toSouthEast());
    if (drawNarrowInteriors && (insetNS > 1 || insetWE > 1))
      drawNarrowInteriors = false;
   
    // let's do it!
    switch (style) {
    case COLUMNS_ONLY:
      drawInteriorColumns(generator, chunk, context, drawNarrowInteriors,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      break;
    case COLUMNS_OFFICES:
      drawInteriorColumns(generator, chunk, context, drawNarrowInteriors,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      drawInteriorRooms(generator, chunk, context, drawNarrowInteriors,
          rooms, floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      break;
    case WALLS_ONLY:
      drawInteriorWalls(generator, chunk, context, drawNarrowInteriors,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      drawInteriorDoors = true;
      break;
    case WALLS_OFFICES:
      drawInteriorWalls(generator, chunk, context, drawNarrowInteriors,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      drawInteriorRooms(generator, chunk, context, drawNarrowInteriors,
          rooms, floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
      drawInteriorDoors = true;
      break;
    case RANDOM:
      if (chunkOdds.flipCoin())
        drawInteriorParts(generator, chunk, context,
            InteriorStyle.COLUMNS_OFFICES, rooms, floor, floorAt, floorHeight,
            insetNS, insetWE, allowRounded,
            materialWall, materialGlass, stairLocation,
            materialStair, materialStairWall, materialPlatform,
            drawStairWall, drawStairs, topFloor, singleFloor,
            heights);
      else
        drawInteriorParts(generator, chunk, context,
            InteriorStyle.WALLS_OFFICES, rooms, floor, floorAt, floorHeight,
            insetNS, insetWE, allowRounded,
            materialWall, materialGlass, stairLocation,
            materialStair, materialStairWall, materialPlatform,
            drawStairWall, drawStairs, topFloor, singleFloor,
            heights);
     
      // all done, don't do anymore
      return;
    }
   
    // fancy walls... maybe
    if (drawStairWall) {
      drawStairsWalls(generator, chunk, floorAt, aboveFloorHeight,
          stairLocation, materialStairWall,
          floor == height - 1, floor == 0 && depth == 0);
    }
   
    // put up more doors?
    if (drawInteriorDoors) {
      drawInteriorDoors(generator, chunk, context, drawNarrowInteriors,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass, stairLocation, heights);
    }
   
    // more stairs and such
    if (drawStairs)
      drawStairs(generator, chunk, floorAt, aboveFloorHeight,
          stairLocation, materialStair, materialPlatform);
   
    // outside
    if (drawExteriorDoors)
      drawExteriorDoors(generator, chunk, context,
          floor, floorAt, floorHeight, insetNS, insetWE,
          allowRounded, materialWall, materialGlass,
          stairLocation, heights);
  }
   
  private void drawInteriorColumns(WorldGenerator generator, RealChunk chunk, DataContext context,
      boolean drawNarrowInteriors, int floor, int y1, int floorHeight,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairLocation, Surroundings heights) {

    // precalculate
    int y2 = y1 + floorHeight;
   
    // first try the narrow logic (single column in the middle)
    if (drawNarrowInteriors) {
      chunk.setBlocks(7, 9, y1, y2, 7, 9, columnMaterial);
     
    // if the narrow logic doesn't handle it, try to use the wide logic (four columns in the middle)
    } else {
     
      if (heights.toNorthWest())
        chunk.setBlocks(4, y1, y2, 4, columnMaterial);
      if (heights.toNorthEast())
        chunk.setBlocks(11, y1, y2, 4, columnMaterial);
      if (heights.toSouthWest())
        chunk.setBlocks(4, y1, y2, 11, columnMaterial);
      if (heights.toSouthEast())
        chunk.setBlocks(11, y1, y2, 11, columnMaterial);
    }
  }
 
  private void drawInteriorWalls(WorldGenerator generator, RealChunk chunk, DataContext context,
      boolean drawNarrowInteriors, int floor, int y1, int floorHeight,
      int insetNS, int insetWE, boolean allowRounded,
      Material wallMaterial, Material glassMaterial,
      StairWell stairsLocation, Surroundings heights) {
   
    //TODO Atrium in the middle of 2x2
   
    // precalculate
    int y2 = y1 + floorHeight;
    int x1 = heights.toWest() ? 0 : insetWE + 1;
    int x2 = chunk.width - (heights.toEast() ? 0 : (insetWE + 1));
    int z1 = heights.toNorth() ? 0 : insetNS + 1;
    int z2 = chunk.width - (heights.toSouth() ? 0 : (insetNS + 1));

    // first try the narrow logic (single wall in the middle)
    if (drawNarrowInteriors) {
     
      // Northward
      if (heights.toNorth()) {
//        materialWall = Material.COBBLESTONE;
//        wallId = (byte) materialWall.getId();
       
        // draw out
        if (stairsLocation == StairWell.NONE) {
          drawInteriorNSWall(chunk, 7, y1, y2, 4, 7, wallMaterial, glassMaterial);
          chunk.setBlocks(7, y1, y2, 7, wallMaterial);
        }
       
        // draw cap
        drawInteriorNSWall(chunk, 7, y1, y2, 1, 4, wallMaterial, glassMaterial);
        drawInteriorWEWall(chunk, x1, 8, y1, y2, 0, wallMaterial, glassMaterial);

      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.BEDROCK;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw short wall
        drawInteriorNSWall(chunk, 7, y1, y2, z1, 8, wallMaterial, glassMaterial);
      }
       
      // Eastward
      if (heights.toEast()) {
//        materialWall = Material.CLAY;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw out
        if (stairsLocation == StairWell.NONE) {
          drawInteriorWEWall(chunk, 9, 12, y1, y2, 7, wallMaterial, glassMaterial);
          chunk.setBlocks(8, y1, y2, 7, wallMaterial);
        }
       
        // draw cap
        drawInteriorWEWall(chunk, 12, 15, y1, y2, 7, wallMaterial, glassMaterial);
        drawInteriorNSWall(chunk, 15, y1, y2, z1, 8, wallMaterial, glassMaterial);
       
      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.SAND;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw short wall
        drawInteriorWEWall(chunk, 8, x2, y1, y2, 7, wallMaterial, glassMaterial);
      }
     
      // Westward
      if (heights.toWest()) {
//        materialWall = Material.IRON_BLOCK;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw out
        if (stairsLocation == StairWell.NONE) {
          drawInteriorWEWall(chunk, 4, 7, y1, y2, 8, wallMaterial, glassMaterial);
          chunk.setBlocks(7, y1, y2, 8, wallMaterial);
        }
       
        // draw cap
        drawInteriorWEWall(chunk, 1, 4, y1, y2, 8, wallMaterial, glassMaterial);
        drawInteriorNSWall(chunk, 0, y1, y2, 8, z2, wallMaterial, glassMaterial);
       
      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.GOLD_BLOCK;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw short wall
        drawInteriorWEWall(chunk, x1, 8, y1, y2, 8, wallMaterial, glassMaterial);
      }
     
      // Southward
      if (heights.toSouth()) {
//        materialWall = Material.DIAMOND_BLOCK;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw out
        if (stairsLocation == StairWell.NONE) {
          drawInteriorNSWall(chunk, 8, 13, y1, y2, 15, wallMaterial, glassMaterial);
          chunk.setBlocks(8, y1, y2, 8, wallMaterial);
        }
       
        // draw cap
        drawInteriorNSWall(chunk, 8, y1, y2, 12, 15, wallMaterial, glassMaterial);
        drawInteriorWEWall(chunk, 8, x2, y1, y2, 15, wallMaterial, glassMaterial);

      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.LAPIS_BLOCK;
//        wallMaterial = (byte) materialWall.getMaterial();
       
        // draw short wall
        drawInteriorNSWall(chunk, 8, y1, y2, 8, z2, wallMaterial, glassMaterial);
      }
     
    // if the narrow logic doesn't handle it, try to use the wide logic (two walls in the middle)
    } else {
   
      // NW corner
      if (heights.toNorthWest()) {
//        wallMaterial = (byte) Material.QUARTZ_ORE.getMaterial();
        if (heights.toNorth()) {
          drawInteriorNSWall(chunk, 4, y1, y2, 0, wallMaterial, glassMaterial);
        }
        if (heights.toWest()) {
          drawInteriorWEWall(chunk, 0, y1, y2, 4, wallMaterial, glassMaterial);
        }
       
      } else {
//        wallMaterial = (byte) Material.BEDROCK.getMaterial();
        if (!heights.toNorth() && heights.toSouth() && heights.toWest()) {
          drawInteriorNSWall(chunk, 4, y1, y2, z1, 8, wallMaterial, glassMaterial);
        } else if (!heights.toWest() && heights.toEast() && heights.toNorth()) {
          drawInteriorWEWall(chunk, x1, 8, y1, y2, 4, wallMaterial, glassMaterial);
        }
      }
     
      // NE corner
      if (heights.toNorthEast()) {
//        wallMaterial = (byte) Material.CLAY.getMaterial();
        if (heights.toEast()) {
          drawInteriorWEWall(chunk, 8, y1, y2, 4, wallMaterial, glassMaterial);
        }
        if (heights.toNorth()) {
          drawInteriorNSWall(chunk, 11, y1, y2, 0, wallMaterial, glassMaterial);
        }
       
      } else {
//        wallMaterial = (byte) Material.SAND.getMaterial();
        if (!heights.toNorth() && heights.toSouth() && heights.toEast()) {
          drawInteriorNSWall(chunk, 11, y1, y2, z1, 8, wallMaterial, glassMaterial);
        } else if (!heights.toEast() && heights.toWest() && heights.toNorth()) {
          drawInteriorWEWall(chunk, 8, x2, y1, y2, 4, wallMaterial, glassMaterial);
        }
      }
     
      // SW corner
      if (heights.toSouthWest()) {
//        wallMaterial = (byte) Material.IRON_BLOCK.getMaterial();
        if (heights.toWest()) {
          drawInteriorWEWall(chunk, 0, y1, y2, 11, wallMaterial, glassMaterial);
        }
        if (heights.toSouth()) {
          drawInteriorNSWall(chunk, 4, y1, y2, 8, wallMaterial, glassMaterial);
        }
       
      } else {
//        wallMaterial = (byte) Material.GOLD_BLOCK.getMaterial();
        if (!heights.toSouth() && heights.toNorth() && heights.toWest()) {
          drawInteriorNSWall(chunk, 4, y1, y2, 8, z2, wallMaterial, glassMaterial);
        } else if (!heights.toWest() && heights.toEast() && heights.toSouth()) {
          drawInteriorWEWall(chunk, x1, 8, y1, y2, 11, wallMaterial, glassMaterial);
        }
      }
     
      // SE corner
      if (heights.toSouthEast()) {
//        wallMaterial = (byte) Material.DIAMOND_BLOCK.getMaterial();
        if (heights.toSouth()) {
          drawInteriorNSWall(chunk, 11, y1, y2, 8, wallMaterial, glassMaterial);
        }
        if (heights.toEast()) {
          drawInteriorWEWall(chunk, 8, y1, y2, 11, wallMaterial, glassMaterial);
        }
      } else {
//        wallMaterial = (byte) Material.LAPIS_BLOCK.getMaterial();
        if (!heights.toSouth() && heights.toNorth() && heights.toEast()) {
          drawInteriorNSWall(chunk, 11, y1, y2, 8, z2, wallMaterial, glassMaterial);
        } else if (!heights.toEast() && heights.toWest() && heights.toSouth()) {
          drawInteriorWEWall(chunk, 8, x2, y1, y2, 11, wallMaterial, glassMaterial);
        }
      }
    }
  }
 
  private void drawInteriorDoors(WorldGenerator generator, RealChunk chunk, DataContext context,
      boolean drawNarrowInteriors, int floor, int y1, int floorHeight,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairsLocation, Surroundings heights) {
   
    // precalculate
    int y2 = y1 + floorHeight;

    // first try the narrow logic (single wall in the middle)
    if (drawNarrowInteriors) {
     
      // Northward
      if (heights.toNorth()) {
//        materialWall = Material.COBBLESTONE;
        //2
        if (stairsLocation == StairWell.NONE)
          drawInteriorNSDoor(chunk, 7, y1, y2, 4, materialWall);
        //1
        drawInteriorWEDoor(chunk, 5, y1, y2, 0, materialWall);

      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.BEDROCK;
        //a
        drawInteriorNSDoor(chunk, 7, y1, y2, 5, materialWall);
      }
       
      // Eastward
      if (heights.toEast()) {
//        materialWall = Material.CLAY;
        //3
        if (stairsLocation == StairWell.NONE)
          drawInteriorWEDoor(chunk, 9, y1, y2, 7, materialWall);
        //4
        drawInteriorNSDoor(chunk, 15, y1, y2, 5, materialWall);
       
      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.SAND;
        //b
        drawInteriorWEDoor(chunk, 8, y1, y2, 7, materialWall);
      }
     
      // Westward
      if (heights.toWest()) {
//        materialWall = Material.IRON_BLOCK;
        //7
        if (stairsLocation == StairWell.NONE)
          drawInteriorWEDoor(chunk, 4, y1, y2, 8, materialWall);
        //8
        drawInteriorNSDoor(chunk, 0, y1, y2, 8, materialWall);
       
      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.GOLD_BLOCK;
        //d
        drawInteriorWEDoor(chunk, 5, y1, y2, 8, materialWall);
      }
     
      // Southward
      if (heights.toSouth()) {
//        materialWall = Material.DIAMOND_BLOCK;
        //6
        if (stairsLocation == StairWell.NONE)
          drawInteriorNSDoor(chunk, 8, y1, y2, 9, materialWall);
        //5
        drawInteriorWEDoor(chunk, 8, y1, y2, 15, materialWall);

      } else if (stairsLocation == StairWell.NONE && !allowRounded) {
//        materialWall = Material.LAPIS_BLOCK;
        //c
        drawInteriorNSDoor(chunk, 8, y1, y2, 8, materialWall);
      }
     
    // if the narrow logic doesn't handle it, try to use the wide logic (two walls in the middle)
    } else {
   
      // NW corner
//      materialWall = Material.QUARTZ_ORE;
      if (heights.toNorthWest()) {
        if (heights.toNorth()) //1
          drawInteriorNSDoor(chunk, 4, y1, y2, 2, materialWall);
        if (heights.toWest()) //2
          drawInteriorWEDoor(chunk, 2, y1, y2, 4, materialWall);
        if (stairsLocation != StairWell.NORTHWEST) {
          //8,8
          drawInteriorWEDoor(chunk, 4, y1, y2, 4, materialWall);
          drawInteriorNSDoor(chunk, 4, y1, y2, 4, materialWall);
        }
//      } else {
//        if (stairsLocation == StairWell.NORTHEAST) //8
//          drawInteriorWEDoor(chunk, 5, y1, y2, 4, materialWall);
//        else if (stairsLocation == StairWell.SOUTHWEST) //8
//          drawInteriorNSDoor(chunk, 4, y1, y2, 5, materialWall);
      }
     
      // NE corner
//      materialWall = Material.IRON_ORE;
      if (heights.toNorthEast()) {
        if (heights.toNorth()) //3
          drawInteriorNSDoor(chunk, 11, y1, y2, 2, materialWall);
        if (heights.toEast()) //4
          drawInteriorWEDoor(chunk, 11, y1, y2, 4, materialWall);
        if (stairsLocation != StairWell.NORTHEAST) {
          //9,10
          drawInteriorWEDoor(chunk, 9, y1, y2, 4, materialWall);
          drawInteriorNSDoor(chunk, 11, y1, y2, 4, materialWall);
        }
//      } else {
//        if (stairsLocation == StairWell.NORTHWEST) //9
//          drawInteriorWEDoor(chunk, 8, y1, y2, 4, materialWall);
//        else if (stairsLocation == StairWell.SOUTHEAST) //10
//          drawInteriorNSDoor(chunk, 11, y1, y2, 5, materialWall);
      }
     
      // SW corner
//      materialWall = Material.GOLD_ORE;
      if (heights.toSouthWest()) {
        if (heights.toSouth()) //6
          drawInteriorNSDoor(chunk, 4, y1, y2, 11, materialWall);
        if (heights.toWest()) //5
          drawInteriorWEDoor(chunk, 2, y1, y2, 11, materialWall);
        if (stairsLocation != StairWell.SOUTHWEST) {
          //13,14
          drawInteriorWEDoor(chunk, 4, y1, y2, 11, materialWall);
          drawInteriorNSDoor(chunk, 4, y1, y2, 9, materialWall);
        }
//      } else {
//        if (stairsLocation == StairWell.NORTHWEST) //14
//          drawInteriorNSDoor(chunk, 4, y1, y2, 8, materialWall);
//        else if (stairsLocation == StairWell.SOUTHEAST) //13
//          drawInteriorWEDoor(chunk, 5, y1, y2, 11, materialWall);
      }
     
      // SE corner
//      materialWall = Material.DIAMOND_ORE;
      if (heights.toSouthEast()) {
        if (heights.toSouth()) //7
          drawInteriorNSDoor(chunk, 11, y1, y2, 11, materialWall);
        if (heights.toEast()) //7
          drawInteriorWEDoor(chunk, 11, y1, y2, 11, materialWall);
        if (stairsLocation != StairWell.SOUTHEAST) {
          //11,12
          drawInteriorWEDoor(chunk, 9, y1, y2, 11, materialWall);
          drawInteriorNSDoor(chunk, 11, y1, y2, 9, materialWall);
        }
//      } else {
//        if (stairsLocation == StairWell.SOUTHWEST) //12
//          drawInteriorWEDoor(chunk, 8, y1, y2, 11, materialWall);
//        else if (stairsLocation == StairWell.NORTHEAST) //11
//          drawInteriorNSDoor(chunk, 11, y1, y2, 8, materialWall);
      }
     
      // backfill with doors near stairs
      switch (stairsLocation) {
      case NORTHWEST:
//        materialWall = Material.DIAMOND_ORE;
        if (!heights.toEast()) //15
          drawInteriorWEDoor(chunk, 7, y1, y2, 4, materialWall);
//        materialWall = Material.DIAMOND_BLOCK;
        if (!heights.toSouth()) //16
          drawInteriorNSDoor(chunk, 4, y1, y2, 7, materialWall);
        break;
      case SOUTHEAST:
//        materialWall = Material.REDSTONE_ORE;
        if (!heights.toNorth()) //17
          drawInteriorNSDoor(chunk, 11, y1, y2, 6, materialWall);
//        materialWall = Material.REDSTONE_BLOCK;
        if (!heights.toWest()) //18
          drawInteriorWEDoor(chunk, 6, y1, y2, 11, materialWall);
        break;
      case NORTHEAST:
//        materialWall = Material.EMERALD_ORE;
        if (!heights.toWest()) //19
          drawInteriorWEDoor(chunk, 6, y1, y2, 4, materialWall);
//        materialWall = Material.EMERALD_BLOCK;
        if (!heights.toSouth()) //20
          drawInteriorNSDoor(chunk, 11, y1, y2, 7, materialWall);
        break;
      case SOUTHWEST:
//        materialWall = Material.GOLD_ORE;
        if (!heights.toNorth()) //21
          drawInteriorNSDoor(chunk, 4, y1, y2, 6, materialWall);
//        materialWall = Material.GOLD_BLOCK;
        if (!heights.toEast()) //22
          drawInteriorWEDoor(chunk, 7, y1, y2, 11, materialWall);
        break;
      default:
        // nothing to draw here
      }
    }
  }
 
  private void drawExteriorDoors(WorldGenerator generator, RealChunk chunk, DataContext context,
      int floor, int y1, int height,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairsLocation, Surroundings heights) {
   
    // precalculate
    int y2 = y1 + height;
    int x1 = heights.toWest() ? 0 : insetWE + 1;
    int x2 = chunk.width - (heights.toEast() ? 0 : (insetWE + 1));
    int z1 = heights.toNorth() ? 0 : insetNS + 1;
    int z2 = chunk.width - (heights.toSouth() ? 0 : (insetNS + 1));

    // rounded potential?
    if (allowRounded) {
      if (heights.toEast() && heights.toSouth())
        drawExteriorWEDoor(chunk, 13, y1, y2, z1 - 1, materialWall);
      if (heights.toWest() && heights.toNorth())
        drawExteriorEWDoor(chunk, 0, y1, y2, z2, materialWall);
      if (heights.toWest() && heights.toSouth())
        drawExteriorNSDoor(chunk, x2, y1, y2, 13, materialWall);
      if (heights.toEast() && heights.toNorth())
        drawExteriorSNDoor(chunk, x1 - 1, y1, y2, 0, materialWall);
    } else {
      if (!heights.toNorth())
        drawExteriorWEDoor(chunk, 5, y1, y2, z1 - 1, materialWall);
      if (!heights.toSouth())
        drawExteriorEWDoor(chunk, 8, y1, y2, z2, materialWall);
      if (!heights.toWest())
        drawExteriorNSDoor(chunk, x1 - 1, y1, y2, 8, materialWall);
      if (!heights.toEast())
        drawExteriorSNDoor(chunk, x2, y1, y2, 5, materialWall);
    }
  }

  private static int maxInsetForRooms = 2;
 
  private void drawInteriorRooms(WorldGenerator generator, RealChunk chunk, DataContext context,
      boolean drawNarrowInteriors, RoomProvider rooms, int floor, int y1, int height,
      int insetNS, int insetWE, boolean allowRounded,
      Material materialWall, Material materialGlass,
      StairWell stairsLocation, Surroundings heights) {
   
    // skip the rooms?
    if (!generator.settings.includeBuildingInteriors)
      return;
   
    // outer rooms?
    boolean includeOuterRooms = insetNS <= maxInsetForRooms || insetWE <= maxInsetForRooms;
   
    // first try the narrow logic (single wall in the middle)
    if (drawNarrowInteriors) {
     
      // don't do these for rounded cases
      if (!allowRounded) {

        // Northward
        if (heights.toNorth())
          drawInteriorRoom(generator, chunk, rooms, floor, 3, y1, 1, height,
              Facing.NORTH, materialWall, materialGlass); //1
        if (insetNS < 2)
          drawInteriorRoom(generator, chunk, rooms, floor, 8, y1, 2, height,
              Facing.WEST, materialWall, materialGlass); //2
         
        // Eastward
        if (heights.toEast())
          drawInteriorRoom(generator, chunk, rooms, floor, 12, y1, 3, height,
              Facing.EAST, materialWall, materialGlass); //3
        if (insetWE < 2)
          drawInteriorRoom(generator, chunk, rooms, floor, 11, y1, 8, height,
              Facing.NORTH, materialWall, materialGlass); //4
       
        // Southward
        if (heights.toSouth())
          drawInteriorRoom(generator, chunk, rooms, floor, 11, y1, 12, height,
              Facing.SOUTH, materialWall, materialGlass); //5
        if (insetNS < 2)
          drawInteriorRoom(generator, chunk, rooms, floor, 5, y1, 11, height,
              Facing.EAST, materialWall, materialGlass); //6
       
        // Westward
        if (heights.toWest())
          drawInteriorRoom(generator, chunk, rooms, floor, 1, y1, 10, height,
              Facing.WEST, materialWall, materialGlass); //7
        if (insetWE < 2)
          drawInteriorRoom(generator, chunk, rooms, floor, 2, y1, 5, height,
              Facing.SOUTH, materialWall, materialGlass); //8
      }
     
    // if the narrow logic doesn't handle it, try to use the wide logic (two walls in the middle)
    } else {
   
      // NW corner
      if (heights.toNorthWest()) {
        if (heights.toNorth() && heights.toWest()) {
          //1 & 2
          drawInteriorRoom(generator, chunk, rooms, floor, 1, y1, 0, height,
              Facing.EAST, materialWall, materialGlass);
          drawInteriorRoom(generator, chunk, rooms, floor, 5, y1, 0, height,
              Facing.WEST, materialWall, materialGlass);
        }
      } else if (includeOuterRooms) {
        if (heights.toNorth()) {
          if (heights.toWest()) {
            //none
          } else if (stairsLocation != StairWell.NORTHWEST ||
              stairsLocation != StairWell.WEST) {
            //n & m
            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 1, height,
                Facing.SOUTH, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 5, height,
                Facing.NORTH, materialWall, materialGlass);
          }
        } else {
          if (heights.toWest() &&
                (stairsLocation != StairWell.NORTHWEST ||
                 stairsLocation != StairWell.NORTH)) {
            //c & d
            drawInteriorRoom(generator, chunk, rooms, floor, 1, y1, 4, height,
                Facing.EAST, materialWall, materialGlass);
//            drawInteriorRoom(generator, chunk, rooms, floor, 5, y1, 4, height,
//                Facing.WEST, materialWall, materialGlass);
          } else if (!allowRounded && stairsLocation == StairWell.SOUTHEAST) {
            //q
            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 4, height,
                Facing.EAST, materialWall, materialGlass);
          }
        }
      }
     
      // NE corner
      if (heights.toNorthEast()) {
        if (heights.toNorth() && heights.toEast()) {
          //3 & 4
          drawInteriorRoom(generator, chunk, rooms, floor, 13, y1, 1, height,
              Facing.SOUTH, materialWall, materialGlass);
          drawInteriorRoom(generator, chunk, rooms, floor, 13, y1, 5, height,
              Facing.NORTH, materialWall, materialGlass);
        }
      } else if (includeOuterRooms) {
        if (heights.toNorth()) {
          if (heights.toEast()) {
            //none
          } else if (stairsLocation != StairWell.NORTHEAST ||
              stairsLocation != StairWell.EAST) {
            //g & h
            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 1, height,
                Facing.SOUTH, materialWall, materialGlass);
//            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 5, height,
//                Facing.NORTH, materialWall, materialGlass);
          }
        } else {
          if (heights.toEast() &&
              (stairsLocation != StairWell.NORTHEAST ||
               stairsLocation != StairWell.NORTH)) {
            //a & b
            drawInteriorRoom(generator, chunk, rooms, floor, 8, y1, 4, height,
                Facing.EAST, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 12, y1, 4, height,
                Facing.WEST, materialWall, materialGlass);
          } else if (!allowRounded && stairsLocation == StairWell.SOUTHWEST) {
            //r
            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 4, height,
                Facing.SOUTH, materialWall, materialGlass);
          }
        }
      }
     
      // SW corner
      if (heights.toSouthWest()) {
        if (heights.toSouth() && heights.toWest()) {
          //5 & 6
          drawInteriorRoom(generator, chunk, rooms, floor, 0, y1, 12, height,
              Facing.NORTH, materialWall, materialGlass);
          drawInteriorRoom(generator, chunk, rooms, floor, 0, y1, 8, height,
              Facing.SOUTH, materialWall, materialGlass);
        }
      } else if (includeOuterRooms) {
        if (heights.toSouth()) {
          if (heights.toWest()) {
            //none
          } else if (stairsLocation != StairWell.SOUTHWEST ||
              stairsLocation != StairWell.WEST) {
            //p & o
//            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 8, height,
//                Facing.SOUTH, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 12, height,
                Facing.NORTH, materialWall, materialGlass);
          }
        } else {
          if (heights.toWest() &&
              (stairsLocation != StairWell.SOUTHWEST ||
               stairsLocation != StairWell.SOUTH)) {

            //j & i
            drawInteriorRoom(generator, chunk, rooms, floor, 1, y1, 9, height,
                Facing.EAST, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 5, y1, 9, height,
                Facing.WEST, materialWall, materialGlass);
          } else if (!allowRounded && stairsLocation == StairWell.NORTHEAST) {
            //t
            drawInteriorRoom(generator, chunk, rooms, floor, 4, y1, 9, height,
                Facing.NORTH, materialWall, materialGlass);
          }
        }
      }
     
      // SE corner
      if (heights.toSouthEast()) {
        if (heights.toSouth() && heights.toEast()) {
          //7 & 8
          drawInteriorRoom(generator, chunk, rooms, floor, 12, y1, 13, height,
              Facing.WEST, materialWall, materialGlass);
          drawInteriorRoom(generator, chunk, rooms, floor, 8, y1, 13, height,
              Facing.EAST, materialWall, materialGlass);
        }
      } else if (includeOuterRooms) {
        if (heights.toSouth()) {
          if (heights.toEast()) {
            //none
          } else if (stairsLocation != StairWell.SOUTHEAST ||
              stairsLocation != StairWell.EAST) {
            //e & f
            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 8, height,
                Facing.SOUTH, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 12, height,
                Facing.NORTH, materialWall, materialGlass);
          }
        } else {
          if (heights.toEast() &&
              (stairsLocation != StairWell.SOUTHEAST ||
               stairsLocation != StairWell.SOUTH)) {

            //l & k
//            drawInteriorRoom(generator, chunk, rooms, floor, 8, y1, 9, height,
//                Facing.EAST, materialWall, materialGlass);
            drawInteriorRoom(generator, chunk, rooms, floor, 12, y1, 9, height,
                Facing.WEST, materialWall, materialGlass);
          } else if (!allowRounded && stairsLocation == StairWell.NORTHWEST) {
            //s
            drawInteriorRoom(generator, chunk, rooms, floor, 9, y1, 9, height,
                Facing.WEST, materialWall, materialGlass);
          }
        }
      }
    }
  }
 
  //TODO I need to actually make this dynamic based on how much room there is
  private static int roomWidth = 3;
  private static int roomDepth = 3;
 
  private void drawInteriorRoom(WorldGenerator generator, RealChunk chunk,
      RoomProvider rooms, int floor, int x, int y, int z, int height,
      Facing sideWithWall, Material materialWall, Material materialGlass) {

    rooms.drawFixtures(generator, chunk, chunkOdds, floor, x, y, z,
        roomWidth, height, roomDepth, sideWithWall, materialWall, materialGlass);
  }
 
  private void drawInteriorNSWall(RealChunk chunk, int x, int y1, int y2, int z, Material wallMaterial, Material glassMaterial) {
    drawInteriorNSWall(chunk, x, y1, y2, z, z + 8, wallMaterial, glassMaterial);
  }
 
  private void drawInteriorWEWall(RealChunk chunk, int x, int y1, int y2, int z, Material wallMaterial, Material glassMaterial) {
    drawInteriorWEWall(chunk, x, x + 8, y1, y2, z, wallMaterial, glassMaterial);
  }
 
  private void drawInteriorNSWall(RealChunk chunk, int x, int y1, int y2, int z1, int z2, Material wallMaterial, Material glassMaterial) {
    BlackMagic.setBlocks(chunk, x, x + 1, y1, y2, z1, z2, wallMaterial, glassMaterial, wallsInterior);
  }
 
  private void drawInteriorWEWall(RealChunk chunk, int x1, int x2, int y1, int y2, int z, Material wallMaterial, Material glassMaterial) {
    BlackMagic.setBlocks(chunk, x1, x2, y1, y2, z, z + 1, wallMaterial, glassMaterial, wallsInterior);
  }
 
  private void drawInteriorNSDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnInteriorDoor))
      drawDoor(chunk, x, x, x, y1, y2, z, z + 1, z + 2, Door.WESTBYNORTHWEST, wall);
  }
 
  private void drawInteriorWEDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnInteriorDoor))
      drawDoor(chunk, x, x + 1, x + 2, y1, y2, z, z, z, Door.NORTHBYNORTHWEST, wall);
  }
 
  private void drawExteriorNSDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnExteriorDoor))
      drawDoor(chunk, x, x, x, y1, y2, z, z + 1, z + 2, Door.WESTBYNORTHWEST, wall);
  }
 
  private void drawExteriorSNDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnExteriorDoor))
      drawDoor(chunk, x, x, x, y1, y2, z, z + 1, z + 2, Door.EASTBYNORTHEAST, wall);
  }

  private void drawExteriorWEDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnExteriorDoor))
      drawDoor(chunk, x, x + 1, x + 2, y1, y2, z, z, z, Door.NORTHBYNORTHWEST, wall);
  }
 
  private void drawExteriorEWDoor(RealChunk chunk, int x, int y1, int y2, int z, Material wall) {
    if (chunkOdds.playOdds(oddsOfAnExteriorDoor))
      drawDoor(chunk, x, x + 1, x + 2, y1, y2, z, z, z, Door.SOUTHBYSOUTHEAST, wall);
  }
 
  //TODO roof fixtures (peak, helipad, air conditioning, stairwells access, penthouse, castle trim, etc.
  protected void drawRoof(WorldGenerator generator, ByteChunk chunk, DataContext context,
      int y1, int insetNS, int insetWE,
      boolean allowRounded, Material material, Surroundings heights) {
    switch (roofStyle) {
    case PEAK:
      if (heights.getNeighborCount() == 0) {
        for (int i = 0; i < aboveFloorHeight; i++) {
          if (i == aboveFloorHeight - 1)
            drawCeilings(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS + i, insetWE + i, allowRounded, material, heights);
          else
            drawExteriorParts(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS + i, insetWE + i, allowRounded, material, material, heights);
        }
      } else
        drawEdgedRoof(generator, chunk, context, y1, insetNS, insetWE, allowRounded, material, true, heights);
      break;
    case TENT_NORTHSOUTH:
      if (heights.getNeighborCount() == 0) {
        for (int i = 0; i < aboveFloorHeight; i++) {
          if (i == aboveFloorHeight - 1)
            drawCeilings(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS + i, insetWE, allowRounded, material, heights);
          else
            drawExteriorParts(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS + i, insetWE, allowRounded, material, material, heights);
        }
      } else
        drawEdgedRoof(generator, chunk, context, y1, insetNS, insetWE, allowRounded, material, true, heights);
      break;
    case TENT_WESTEAST:
      if (heights.getNeighborCount() == 0) {
        for (int i = 0; i < aboveFloorHeight; i++) {
          if (i == aboveFloorHeight - 1)
            drawCeilings(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS, insetWE + i, allowRounded, material, heights);
          else
            drawExteriorParts(generator, chunk, context, y1 + i * roofScale, roofScale, insetNS, insetWE + i, allowRounded, material, material, heights);
        }
      } else
        drawEdgedRoof(generator, chunk, context, y1, insetNS, insetWE, allowRounded, material, true, heights);
      break;
    case EDGED:
      drawEdgedRoof(generator, chunk, context, y1, insetNS, insetWE, allowRounded, material, true, heights);
      break;
    case FLATTOP:
      drawEdgedRoof(generator, chunk, context, y1, insetNS, insetWE, allowRounded, material, false, heights);
      break;
    }
  }
 
  private void drawEdgedRoof(WorldGenerator generator, ByteChunk chunk, DataContext context,
      int y1, int insetNS, int insetWE,
      boolean allowRounded, Material material, boolean doEdge, Surroundings heights) {
   
    // a little bit of edge
    if (doEdge)
      drawExteriorParts(generator, chunk, context, y1, 1, insetNS, insetWE, allowRounded, material, material, heights);
   
    // add the special features
    switch (roofFeature) {
    case ANTENNAS:
      if (heights.getNeighborCount() == 0) {
        drawAntenna(chunk, 6, y1, 6);
        drawAntenna(chunk, 6, y1, 9);
        drawAntenna(chunk, 9, y1, 6);
        drawAntenna(chunk, 9, y1, 9);
        break;
      } // else fall into the conditioners block
    case CONDITIONERS:
      drawConditioner(chunk, 6, y1, 6);
      drawConditioner(chunk, 6, y1, 9);
      drawConditioner(chunk, 9, y1, 6);
      drawConditioner(chunk, 9, y1, 9);
      break;
    case TILE:
      drawCeilings(generator, chunk, context, y1, 1, insetNS + 1, insetWE + 1, allowRounded, tileMaterial, heights);
      break;
    }
  }
 
  private void drawAntenna(ByteChunk chunk, int x, int y, int z) {
   
    if (chunkOdds.flipCoin()) {
      int y2 = y + 8 + chunkOdds.getRandomInt(8);
      chunk.setBlocks(x, y, y + 3, z, antennaBase);
      chunk.setBlocks(x, y + 2, y2, z, antenna);
      if (y2 >= navLightY) {
        navLightX = x;
        navLightY = y2 - 1;
        navLightZ = z;
      }
    }
  }
 
  protected void drawNavLight(RealChunk chunk, DataContext context) {
    if (navLightY > 0)
      chunk.setTorch(navLightX, navLightY, navLightZ, context.torchMat, Direction.Torch.FLOOR);
  }
 
  private void drawConditioner(ByteChunk chunk, int x, int y, int z) {
   
    //TODO air conditioner tracks are not round
    if (chunkOdds.flipCoin()) {
      chunk.setBlock(x, y, z, conditioner);
      chunk.setBlock(x, y + 1, z, conditionerTrim);
      if (chunkOdds.flipCoin()) {
        chunk.setBlockIfAir(x - 1, y, z, duct);
        chunk.setBlockIfAir(x - 2, y, z, duct);
      }
      if (chunkOdds.flipCoin()) {
        chunk.setBlockIfAir(x + 1, y, z, duct);
        chunk.setBlockIfAir(x + 2, y, z, duct);
      }
      if (chunkOdds.flipCoin()) {
        chunk.setBlockIfAir(x, y, z - 1, duct);
        chunk.setBlockIfAir(x, y, z - 2, duct);
      }
      if (chunkOdds.flipCoin()) {
        chunk.setBlockIfAir(x, y, z + 1, duct);
        chunk.setBlockIfAir(x, y, z + 2, duct);
      }
      if (chunkOdds.flipCoin()) {
        chunk.setBlock(x, y, z, conditioner);
        chunk.setBlock(x, y + 1, z, conditionerTrim);
//      } else {
//        chunk.setBlocks(x, x + 2, y, z, z + 2, conditioner);
//        chunk.setBlocks(x, x + 2, y + 1, z, z + 2, conditionerGrill);
      }
    }
  }
 
  private void drawDoor(RealChunk chunk, int x1, int x2, int x3, int y1, int y2, int z1, int z2, int z3,
      Direction.Door direction, Material wallMaterial) {
   
    // frame the door
    chunk.setBlocks(x1, y1, y2, z1, wallMaterial);
    chunk.setBlocks(x2, y1 + 2, y2, z2, wallMaterial);
    chunk.setBlocks(x3, y1, y2, z3, wallMaterial);
   
    // place the door
    chunk.setWoodenDoor(x2, y1, z2, direction);
  }
 
  static class StairAt {
    public int X = 0;
    public int Z = 0;
   
    private static final int stairWidth = 4;
    private static final int centerX = 8;
    private static final int centerZ = 8;
   
    public StairAt(RealChunk chunk, int stairLength, StairWell where) {
      switch (where) {
      case NORTHWEST:
        X = centerX - stairLength;
        Z = centerZ - stairWidth;
        break;
      case NORTH:
        X = centerX - stairLength / 2;
        Z = centerZ - stairWidth;
        break;
      case NORTHEAST:
        X = centerX;
        Z = centerZ - stairWidth;
        break;
      case EAST:
        X = centerX;
        Z = centerZ - stairWidth / 2;
        break;
      case SOUTHEAST:
        X = centerX;
        Z = centerZ;
        break;
      case SOUTH:
        X = centerX - stairLength / 2;
        Z = centerZ;
        break;
      case SOUTHWEST:
        X = centerX - stairLength;
        Z = centerZ;
        break;
      case WEST:
        X = centerX - stairLength;
        Z = centerZ - stairWidth / 2;
        break;
      case CENTER:
      case NONE:
        X = centerX - stairLength / 2;
        Z = centerZ - stairWidth / 2;
        break;
      }
    }
  }

  public StairWell getStairWellLocation(boolean allowRounded, Surroundings heights) {
    if (heights.toNorth() && heights.toWest() && !heights.toSouth() && !heights.toEast())
      return StairWell.NORTHWEST;
    else if (heights.toNorth() && heights.toEast() && !heights.toSouth() && !heights.toWest())
      return StairWell.NORTHEAST;
    else if (heights.toSouth() && heights.toWest() && !heights.toNorth() && !heights.toEast())
      return StairWell.SOUTHWEST;
    else if (heights.toSouth() && heights.toEast() && !heights.toNorth() && !heights.toWest())
      return StairWell.SOUTHEAST;
    else if (heights.toNorth() && heights.toWest() && heights.toEast() && !heights.toSouth())
      return StairWell.NORTH;
    else if (heights.toSouth() && heights.toWest() && heights.toEast() && !heights.toNorth())
      return StairWell.SOUTH;
    else if (heights.toWest() && heights.toNorth() && heights.toSouth() && !heights.toEast())
      return StairWell.WEST;
    else if (heights.toEast() && heights.toNorth() && heights.toSouth() && !heights.toWest())
      return StairWell.EAST;
    else
      return StairWell.CENTER;
  }
 
  protected void drawStairs(WorldGenerator generator, RealChunk chunk, int y1,
      int floorHeight, StairWell where, Material stairMaterial, Material platformMaterial) {
    StairAt at = new StairAt(chunk, floorHeight, where);
    switch (stairStyle) {
    case CROSSED:
      if (floorHeight == 4) {
        switch (stairDirection) {
        case NORTH:
        case SOUTH:
          chunk.setStair(at.X + 1, y1, at.Z + 3, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 2, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 1, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 1, y1 + 3, at.Z, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 2, y1, at.Z, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 1, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 2, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 2, y1 + 3, at.Z + 3, stairMaterial, Stair.SOUTH);
          break;
        case WEST:
        case EAST:
          chunk.setStair(at.X + 3, y1, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X, y1 + 3, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X, y1, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 3, y1 + 3, at.Z + 2, stairMaterial, Stair.EAST);
          break;
        }
       
        return;
      }
      break;
    case LANDING:
      if (floorHeight == 4) {
        switch (stairDirection) {
        case NORTH:
          chunk.setStair(at.X + 1, y1,    at.Z, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 1, stairMaterial, Stair.SOUTH);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 1, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 2, y1 + 3, at.Z, stairMaterial, Stair.NORTH);
          break;
        case SOUTH:
          chunk.setStair(at.X + 2, y1,    at.Z + 3, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 2, stairMaterial, Stair.NORTH);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 2, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 1, y1 + 3, at.Z + 3, stairMaterial, Stair.SOUTH);
          break;
        case WEST:
          chunk.setStair(at.X,    y1,    at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X     , y1 + 3, at.Z + 1, stairMaterial, Stair.WEST);
          break;
        case EAST:
          chunk.setStair(at.X + 3, y1,    at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 3, y1 + 3, at.Z + 2, stairMaterial, Stair.EAST);
          break;
        }

        return;
     
      break;
    case CORNER:
      if (floorHeight == 4) {
        switch (stairDirection) {
        case NORTH:
          chunk.setStair(at.X + 3,     y1, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 2, stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 1, y1 + 3, at.Z + 3, stairMaterial, Stair.SOUTH);
          break;
        case SOUTH:
          chunk.setStair(at.X,     y1,     at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 1, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 2, y1 + 3, at.Z,     stairMaterial, Stair.NORTH);
          break;
        case WEST:
          chunk.setStair(at.X + 1,     y1, at.Z,     stairMaterial, Stair.SOUTH);
          chunk.setStair(at.X + 1, y1 + 1, at.Z + 1, stairMaterial, Stair.SOUTH);
          chunk.setBlock(at.X + 1, y1 + 1, at.Z + 2, platformMaterial);
          chunk.setStair(at.X + 2, y1 + 2, at.Z + 2, stairMaterial, Stair.EAST);
          chunk.setStair(at.X + 3, y1 + 3, at.Z + 2, stairMaterial, Stair.EAST);
          break;
        case EAST:
          chunk.setStair(at.X + 2,     y1, at.Z + 3, stairMaterial, Stair.NORTH);
          chunk.setStair(at.X + 2, y1 + 1, at.Z + 2, stairMaterial, Stair.NORTH);
          chunk.setBlock(at.X + 2, y1 + 1, at.Z + 1, platformMaterial);
          chunk.setStair(at.X + 1, y1 + 2, at.Z + 1, stairMaterial, Stair.WEST);
          chunk.setStair(at.X,     y1 + 3, at.Z + 1, stairMaterial, Stair.WEST);
          break;
        }

        return;
     
      break;
    case STUDIO_A:
      // fall through to the next generator, the one who can deal with variable heights
      break;
    }
   
    // Studio_A
    int y2 = y1 + floorHeight - 1;
    switch (stairDirection) {
    case NORTH:
      for (int i = 0; i < floorHeight; i++) {
        emptyBlock(generator, chunk, at.X + 1, y2, at.Z + i);
        emptyBlock(generator, chunk, at.X + 2, y2, at.Z + i);
        chunk.setStair(at.X + 1, y1 + i, at.Z + i, stairMaterial, Stair.SOUTH);
        chunk.setStair(at.X + 2, y1 + i, at.Z + i, stairMaterial, Stair.SOUTH);
      }
      break;
    case SOUTH:
      for (int i = 0; i < floorHeight; i++) {
        emptyBlock(generator, chunk, at.X + 1, y2, at.Z + i);
        emptyBlock(generator, chunk, at.X + 2, y2, at.Z + i);
        chunk.setStair(at.X + 1, y1 + i, at.Z + floorHeight - i - 1, stairMaterial, Stair.NORTH);
        chunk.setStair(at.X + 2, y1 + i, at.Z + floorHeight - i - 1, stairMaterial, Stair.NORTH);
      }
      break;
    case WEST:
      for (int i = 0; i < floorHeight; i++) {
        emptyBlock(generator, chunk, at.X + i, y2, at.Z + 1);
        emptyBlock(generator, chunk, at.X + i, y2, at.Z + 2);
        chunk.setStair(at.X + i, y1 + i, at.Z + 1, stairMaterial, Stair.EAST);
        chunk.setStair(at.X + i, y1 + i, at.Z + 2, stairMaterial, Stair.EAST);
      }
      break;
    case EAST:
      for (int i = 0; i < floorHeight; i++) {
        emptyBlock(generator, chunk, at.X + i, y2, at.Z + 1);
        emptyBlock(generator, chunk, at.X + i, y2, at.Z + 2);
        chunk.setStair(at.X + floorHeight - i - 1, y1 + i, at.Z + 1, stairMaterial, Stair.WEST);
        chunk.setStair(at.X + floorHeight - i - 1, y1 + i, at.Z + 2, stairMaterial, Stair.WEST);
      }
      break;
    }
  }
 
  private void emptyBlock(WorldGenerator generator, RealChunk chunk, int x, int y, int z) {
    chunk.setBlock(x, y, z, getAirMaterial(generator, y));
   
  }
 
  private void emptyBlocks(WorldGenerator generator, RealChunk chunk, int x1, int x2, int y1, int y2, int z1, int z2) {
    for (int y = y1; y < y2; y++) {
      chunk.setBlocks(x1, x2, y, y + 1, z1, z2, getAirMaterial(generator, y));
    }
  }

  protected void drawStairsWalls(WorldGenerator generator, RealChunk chunk, int y1,
      int floorHeight, StairWell where, Material wallMaterial, boolean isTopFloor, boolean isBottomFloor) {
    StairAt at = new StairAt(chunk, floorHeight, where);
    int y2 = y1 + floorHeight - 1;
    int yClear = y2 + (isTopFloor ? 0 : 1);
    switch (stairStyle) {
    case CROSSED:
      if (floorHeight == 4) {
        switch (stairDirection) {
        case NORTH:
        case SOUTH:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, yClear, at.Z, at.Z + 4);
          chunk.setBlocks(at.X, at.X + 1, y1, y2, at.Z, at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 3, at.X + 4, y1, y2, at.Z, at.Z + 4, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 2, y1 - 1, at.Z, TrapDoor.TOP_NORTH);
            chunk.setTrapDoor(at.X + 1, y1 - 1, at.Z + 3, TrapDoor.TOP_SOUTH);
            chunk.setBlocks(at.X + 2, y1, y2, at.Z, wallMaterial);
            chunk.setBlocks(at.X + 1, y1, y2, at.Z + 3, wallMaterial);
          }
          break;
        case WEST:
        case EAST:
          emptyBlocks(generator, chunk, at.X, at.X + 4, y1, yClear, at.Z + 1, at.Z + 3);
          chunk.setBlocks(at.X, at.X + 4, y1, y2, at.Z, at.Z + 1, wallMaterial);
          chunk.setBlocks(at.X, at.X + 4, y1, y2, at.Z + 3, at.Z + 4, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X, y1 - 1, at.Z + 2, TrapDoor.TOP_WEST);
            chunk.setTrapDoor(at.X + 3, y1 - 1, at.Z + 1, TrapDoor.TOP_EAST);
            chunk.setBlocks(at.X, y1, y2, at.Z + 2, wallMaterial);
            chunk.setBlocks(at.X + 3, y1, y2, at.Z + 1, wallMaterial);
          }
          break;
        }
       
        return;
      }
      break;
    case LANDING:
      if (floorHeight == 4) {
        switch (stairDirection) {
        case NORTH:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, yClear, at.Z,     at.Z + 3);
          chunk.setBlocks(at.X,     at.X + 1, y1, y2,     at.Z,     at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 3, at.X + 4, y1, y2,     at.Z,     at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 1, at.X + 3, y1, y2,     at.Z + 3, at.Z + 4, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 1, y1 - 1, at.Z, TrapDoor.TOP_NORTH);
            chunk.setBlocks(at.X + 1, y1, y2, at.Z, wallMaterial);
          }
          break;
        case SOUTH:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, yClear, at.Z + 1, at.Z + 4);
          chunk.setBlocks(at.X,     at.X + 1, y1, y2,   at.Z,     at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 3, at.X + 4, y1, y2,   at.Z,     at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 1, at.X + 3, y1, y2,   at.Z,     at.Z + 1, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 2, y1 - 1, at.Z + 3, TrapDoor.TOP_SOUTH);
            chunk.setBlocks(at.X + 2, y1, y2, at.Z + 3, wallMaterial);
          }
          break;
        case WEST:
          emptyBlocks(generator, chunk, at.X,     at.X + 3, y1, yClear, at.Z + 1, at.Z + 3);
          chunk.setBlocks(at.X,     at.X + 4, y1, y2,   at.Z,     at.Z + 1, wallMaterial);
          chunk.setBlocks(at.X,     at.X + 4, y1, y2,   at.Z + 3, at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X + 3, at.X + 4, y1, y2,   at.Z + 1, at.Z + 3, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X, y1 - 1, at.Z + 2, TrapDoor.TOP_WEST);
            chunk.setBlocks(at.X, y1, y2, at.Z + 2, wallMaterial);
          }
          break;
        case EAST:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 4, y1, yClear, at.Z + 1, at.Z + 3);
          chunk.setBlocks(at.X,     at.X + 4, y1, y2,   at.Z,     at.Z + 1, wallMaterial);
          chunk.setBlocks(at.X,     at.X + 4, y1, y2,   at.Z + 3, at.Z + 4, wallMaterial);
          chunk.setBlocks(at.X,     at.X + 1, y1, y2,   at.Z + 1, at.Z + 3, wallMaterial);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 3, y1 - 1, at.Z + 1, TrapDoor.TOP_EAST);
            chunk.setBlocks(at.X + 3, y1, y2, at.Z + 1, wallMaterial);
          }
          break;
        }

        return;
     
      break;
    case CORNER:
      if (floorHeight == 4) {
        chunk.setBlocks(at.X, at.X + 4, y1, y2, at.Z, at.Z + 4, wallMaterial);
        switch (stairDirection) {
        case NORTH:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 4, y1, yClear, at.Z + 1, at.Z + 2);
          emptyBlocks(generator, chunk, at.X + 1, at.X + 2, y1, yClear, at.Z + 2, at.Z + 4);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 3, y1 - 1, at.Z + 1, TrapDoor.TOP_EAST);
            chunk.setBlocks(at.X + 3, y1, y2, at.Z + 1, wallMaterial);
          }
          break;
        case SOUTH:
          emptyBlocks(generator, chunk, at.X,     at.X + 3, y1, yClear, at.Z + 2, at.Z + 3);
          emptyBlocks(generator, chunk, at.X + 2, at.X + 3, y1, yClear, at.Z,     at.Z + 2);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X, y1 - 1, at.Z + 2, TrapDoor.TOP_WEST);
            chunk.setBlocks(at.X, y1, y2, at.Z + 2, wallMaterial);
          }
          break;
        case WEST:
          emptyBlocks(generator, chunk, at.X + 1, at.X + 2, y1, yClear, at.Z,     at.Z + 3);
          emptyBlocks(generator, chunk, at.X + 2, at.X + 4, y1, yClear, at.Z + 2, at.Z + 3);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 1, y1 - 1, at.Z, TrapDoor.TOP_NORTH);
            chunk.setBlocks(at.X + 1, y1, y2, at.Z, wallMaterial);
          }
          break;
        case EAST:
          emptyBlocks(generator, chunk, at.X,     at.X + 3, y1, yClear, at.Z + 1, at.Z + 2);
          emptyBlocks(generator, chunk, at.X + 2, at.X + 3, y1, yClear, at.Z + 2, at.Z + 4);
          if (isTopFloor) {
            chunk.setTrapDoor(at.X + 2, y1 - 1, at.Z + 3, TrapDoor.TOP_SOUTH);
            chunk.setBlocks(at.X + 2, y1, y2, at.Z + 3, wallMaterial);
          }
          break;
        }
        return;
     
      break;
    case STUDIO_A:
      // fall through to the next generator, the one who can deal with variable heights
      break;
    }
   
    // Studio_A
    switch (stairDirection) {
    case NORTH:
      emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, y2, at.Z, at.Z + 1);
      emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, y2, at.Z + floorHeight - 1, at.Z + floorHeight);
      chunk.setBlocks(at.X, at.X + 1, y1, y2, at.Z, at.Z + floorHeight, wallMaterial);
      chunk.setBlocks(at.X + 3, at.X + 4, y1, y2, at.Z, at.Z + floorHeight, wallMaterial);
      if (isTopFloor) {
        chunk.setTrapDoor(at.X + 1, y1 - 1, at.Z, TrapDoor.TOP_NORTH);
        chunk.setTrapDoor(at.X + 2, y1 - 1, at.Z, TrapDoor.TOP_NORTH);
        chunk.setBlocks(at.X + 1, at.X + 3, y1, y2, at.Z, at.Z + 1, wallMaterial);
      }
      if (isBottomFloor) {
        chunk.setBlocks(at.X + 1, at.X + 3, y1, y2, at.Z + floorHeight - 1, at.Z + floorHeight, wallMaterial);
      }
      break;
    case SOUTH:
      emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, y2, at.Z, at.Z + 1);
      emptyBlocks(generator, chunk, at.X + 1, at.X + 3, y1, y2, at.Z + floorHeight - 1, at.Z + floorHeight);
      chunk.setBlocks(at.X, at.X + 1, y1, y2, at.Z, at.Z + floorHeight, wallMaterial);
      chunk.setBlocks(at.X + 3, at.X + 4, y1, y2, at.Z, at.Z + floorHeight, wallMaterial);
      if (isTopFloor) {
        chunk.setTrapDoor(at.X + 1, y1 - 1, at.Z + floorHeight - 1, TrapDoor.TOP_SOUTH);
        chunk.setTrapDoor(at.X + 2, y1 - 1, at.Z + floorHeight - 1, TrapDoor.TOP_SOUTH);
        chunk.setBlocks(at.X + 1, at.X + 3, y1, y2, at.Z + floorHeight - 1, at.Z + floorHeight, wallMaterial);
      }
      if (isBottomFloor) {
        chunk.setBlocks(at.X + 1, at.X + 3, y1, y2, at.Z, at.Z + 1, wallMaterial);
      }
      break;
    case WEST:
      emptyBlocks(generator, chunk, at.X, at.X + 1, y1, y2, at.Z + 1, at.Z + 3);
      emptyBlocks(generator, chunk, at.X + floorHeight - 1, at.X + floorHeight, y1, y2, at.Z + 1, at.Z + 3);
      chunk.setBlocks(at.X, at.X + floorHeight, y1, y2, at.Z, at.Z + 1, wallMaterial);
      chunk.setBlocks(at.X, at.X + floorHeight, y1, y2, at.Z + 3, at.Z + 4, wallMaterial);
      if (isTopFloor) {
        chunk.setTrapDoor(at.X, y1 - 1, at.Z + 1, TrapDoor.TOP_WEST);
        chunk.setTrapDoor(at.X, y1 - 1, at.Z + 2, TrapDoor.TOP_WEST);
        chunk.setBlocks(at.X, at.X + 1, y1, y2, at.Z + 1, at.Z + 3, wallMaterial);
      }
      if (isBottomFloor) {
        chunk.setBlocks(at.X + floorHeight - 1, at.X + floorHeight, y1, y2, at.Z + 1, at.Z + 3, wallMaterial);
      }
      break;
    case EAST:
      emptyBlocks(generator, chunk, at.X, at.X + 1, y1, y2, at.Z + 1, at.Z + 3);
      emptyBlocks(generator, chunk, at.X + floorHeight - 1, at.X + floorHeight, y1, y2, at.Z + 1, at.Z + 3);
      chunk.setBlocks(at.X, at.X + floorHeight, y1, y2, at.Z, at.Z + 1, wallMaterial);
      chunk.setBlocks(at.X, at.X + floorHeight, y1, y2, at.Z + 3, at.Z + 4, wallMaterial);
      if (isTopFloor) {
        chunk.setTrapDoor(at.X + floorHeight - 1, y1 - 1, at.Z + 1, TrapDoor.TOP_EAST);
        chunk.setTrapDoor(at.X + floorHeight - 1, y1 - 1, at.Z + 2, TrapDoor.TOP_EAST);
        chunk.setBlocks(at.X + floorHeight - 1, at.X + floorHeight, y1, y2, at.Z + 1, at.Z + 3, wallMaterial);
      }
      if (isBottomFloor) {
        chunk.setBlocks(at.X, at.X + 1, y1, y2, at.Z + 1, at.Z + 3, wallMaterial);
      }
      break;
    }
  };

  protected void drawOtherPillars(RealChunk chunk, int y1, int floorHeight,
      StairWell where, Material wallMaterial) {
    int y2 = y1 + floorHeight - 1;
    if (where != StairWell.SOUTHWEST)
      chunk.setBlocks(3, 5, y1, y2 , 3, 5, wallMaterial);
    if (where != StairWell.SOUTHEAST)
      chunk.setBlocks(3, 5, y1, y2, 11, 13, wallMaterial);
    if (where != StairWell.NORTHWEST)
      chunk.setBlocks(11, 13, y1, y2, 3, 5, wallMaterial);
    if (where != StairWell.NORTHEAST)
      chunk.setBlocks(11, 13, y1, y2, 11, 13, wallMaterial);
  }

  protected void drawFence(WorldGenerator generator, ByteChunk chunk, DataContext context, int inset, int y1, Surroundings neighbors) {
   
    // actual fence
    drawExteriorParts(generator, chunk, context, y1, fenceHeight, inset, inset,
        false, fenceMaterial, fenceMaterial, neighbors);
   
    // holes in fence
    int i = 4 + chunkOdds.getRandomInt(chunk.width / 2);
    int y2 = y1 + fenceHeight;
    Material emptyMaterial = getAirMaterial(generator, y1);
    if (chunkOdds.flipCoin() && !neighbors.toWest())
      chunk.setBlocks(inset, y1, y2, i, emptyMaterial);
    if (chunkOdds.flipCoin() && !neighbors.toEast())
      chunk.setBlocks(chunk.width - 1 - inset, y1, y2, i, emptyMaterial);
    if (chunkOdds.flipCoin() && !neighbors.toNorth())
      chunk.setBlocks(i, y1, y2, inset, emptyMaterial);
    if (chunkOdds.flipCoin() && !neighbors.toSouth())
      chunk.setBlocks(i, y1, y2, chunk.width - 1 - inset, emptyMaterial);
  }
}
TOP

Related Classes of me.daddychurchill.CityWorld.Plats.BuildingLot

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.