Def AnyWall() Or(On("wood_wall"), On("castle_wall")) End
Def AnyFloor() And(Not AnyWall(), Or(On("stone_floor"), On("wood_floor"), On("floor"))) End
Def AnyDoor() Or(On("wood_door"), On("iron_door"), On("iron_gate"), On("wood_gate")) End
Def AnyWater() Or(On("lava"), On("water")) End

Def NextTo(Pred)
  Area(1, Pred)
End

Def FurnitureLoc()
 And(Not NextTo(AnyDoor()), AnyFloor())
End


Def Connector()
  Connect(AnyFloor(),
    (1000, On("no_dig"), None),
    (10, And(On("wood_wall"), Not On("no_dig")), { Remove("wood_wall") Set("clear_middle", "wood_door")}),
    (10, And(On("castle_wall"), Not On("no_dig")), { Remove("castle_wall") Set("clear_middle", "iron_door")}),
    (8, On("lava"), Set("stone_bridge")),
    (8, On("water"), Set("wood_bridge")),
    (6, And(Not AnyWall(), Not AnyWater(), Not AnyFloor(), Not On("no_dig"), On("room_wall")),
        Filter(And(Chance(0.4), Not NextTo(On("wood_door"))), Reset("wood_door"), Reset("floor"))),
    (4, And(Not AnyWall(), Not AnyFloor(), Or(On("rock"), On("hard_rock")),
            Not On("no_dig"), Not On("room_wall")), Reset("floor"))
  )
End

Def Margin(Size, Gen1, Gen2)
  Margins(Size, Gen1, Gen2)
End

Def Margin(Position, Size, Gen1, Gen2)
  MarginImpl(Position, Size, Gen1, Gen2)
End

Def Inside(Size, Gen)
  Margin(Size, None, Gen)
End

Def Inside(Pos, Size, Gen)
  Margin(Pos, Size, None, Gen)
End

Def Border(Size, Gen)
  Margin(Size, Gen, None)
End

Def Border(Pos, Size, Gen)
  Margin(Pos, Size, Gen, None)
End

Def Building(WallType, FloorType) {
  Margin(1,
    Set(FloorType, WallType),
    Reset(FloorType, "clear_middle")
  )
}
End

Def CellularAutomaton(Generator, BeginProb)
  Inside(1, {
    Filter(Chance(BeginProb), Set("cell_added"))
    Repeat(4, {
      Filter(Area(1, On("cell_added"), 5), Set("cell_added2"))
      Filter(On("cell_added2"), Set("cell_added"), Remove("cell_added"))
      Remove("cell_added2")
    })
    Filter(On("cell_added"), Generator)
    Remove("cell_added")
  })
End

Def Village1() {
  Position(
    position = MIDDLE,
    minSize = { 5 6 }
    maxSize = { 8 9 }
    generator = {
      Building("castle_wall", "stone_floor")
      Filter(AnyFloor(), Set("main_building_inside"))
      Inside(-1, Set("main_building"))
    }
  )
  Place(
    minSize = {3 3}
    maxSize = {6 6}
    generator = Building("wood_wall", "floor")
    count = 3
    minSpacing = 1
    predicate = Not On("main_building")
  )
  Connector()
  Place(
    ({1 1} Set("bed") {2 4} And(On("main_building_inside"), NextTo(AnyWall()), Not NextTo(AnyDoor()))),
    ({1 1} Set("stockpile") {1 3} And(On("main_building_inside"), NextTo(AnyWall()), Not NextTo(AnyDoor())))
  )
  Place({1 1} Set("dining_table") 1 And(On("main_building_inside"), Not NextTo(AnyWall())))
}
End

Def Village2() {
  Position(
    position = MIDDLE
    size = {6 9}
    generator = {
      Building("castle_wall", "stone_floor")
      Inside(1, SplitV(0.6,
        Margin(BOTTOM, 1, Set("castle_wall"), Set("first_room")),
        Set("second_room")))
      Inside(-1, Set("main_building"))
    }
  )
  Place(
    minSize = {4 4}
    maxSize = {6 6}
    generator = Building("wood_wall", "floor")
    count = 1
    minSpacing = 1
    predicate = Not On("main_building")
  )
  Connector()
  Place(
    ({1 1} Set("bed") {2 4} And(On("first_room"), NextTo(AnyWall()), Not NextTo(AnyDoor()))),
    ({1 1} Set("stockpile") {1 3} And(On("first_room"), NextTo(AnyWall()), Not NextTo(AnyDoor())))
  )
  Place({1 1}, Set("dining_table"), 1, And(On("second_room"), Not NextTo(AnyWall())))
}
End

"village" Choose(
  Village1(),
  Village2()
)

"village1" Village1()
"village2" Village2()

Def CastleGate1() 
  Border(TOP, 1, Position(MIDDLE, {2 1}, Reset("floor", "iron_gate")))
End

Def GatePlusWall(WallLength)
  Margin(LEFT, WallLength,
    Set("castle_wall"),
    Margin(RIGHT, WallLength,
      Set("castle_wall"),
      Reset("floor", "iron_gate")
    )
  )
End

Def CastleGate2() {
  Inside(TOP, -1, Border(TOP, 1, Position(MIDDLE, {4 1}, GatePlusWall(1))))
  Border(TOP, 1, Position(MIDDLE, {2 1}, Reset("floor")))
}
End

Def CastleGate3() {
  Inside(TOP, -1, Border(TOP, 1, Position(MIDDLE, {6 1}, GatePlusWall(2))))
  Border(TOP, 1, Position(MIDDLE, {4 1}, Reset("floor")))
}
End

Def CastleCorners(CornerSize) {
  Corners(Border(-1, Set("castle_wall")), CornerSize)
  Corners(Reset("floor", "castle_corner"), CornerSize)
  Inside(1, Corners(Choose(None, Reset("floor")), CornerSize))
}
End

Def CastleCornersOpen(CornerSize) {
  Corners(Border(-1, Set("castle_wall")), CornerSize)
  Corners(Reset("floor", "castle_corner"), CornerSize)
  Inside(1, Corners(Reset("floor"), CornerSize))
}
End

Def CastlePart1(Width) {
  SplitV(0.6, Inside(TOP, 1, Inside(BOTTOM, -1, {
    Border(BOTTOM, 1, Set("castle_wall"))
    Position(MIDDLE_V, {Width 1},
      Margin(LEFT, 1,
        Reset("castle_wall"),
        Margin(RIGHT, 1,
          Reset("castle_wall"),
          Reset("floor"))
      )
    )
  })), None)
}
End

Def CastlePart2(Width) {
  SplitV(0.6, None, {
    Border(TOP, 1, Set("castle_wall"))
    Margin(TOP, 2,
      Inside(BOTTOM, -1,
        Position(
          MIDDLE_V,
          {Width 1},
          Margin(LEFT, 1,
            Reset("castle_wall"),
            Margin(RIGHT, 1,
              Reset("castle_wall"),
              Reset("floor"))
          )
        )
      ),
      Position(
        MIDDLE_V,
        {Width 1},
        Inside(LEFT, 1, Inside(RIGHT, 1,
          Margin(LEFT, 1,
            Reset("castle_wall"),
            Border(RIGHT, 1,
              Reset("castle_wall"))
          )
        ))
      ))
  })
}
End

Def CastlePart3(Width) {
  SplitV(0.6, None,
    Inside(TOP, 2,
      Position(
        MIDDLE_V,
        {Width 1},
        Margin(TOP, 1, {
            Set("castle_wall")
            Position(MIDDLE, {2 1}, Reset("floor", "iron_gate"))
          },
          Margin(LEFT, 1,
            Reset("castle_wall"),
            Border(RIGHT, 1, Reset("castle_wall"))))
      )
    )
  )
}
End

Def Maybe(Chance, Gen)
  Choose(Chance Gen, None)
End

Def CastleMaybe(Gen) 
  Maybe(0.5, Gen)
End

Def Castle(CornerSize) {
  Inside(1, {
    Building("castle_wall", "floor")
    Choose(CastleGate3(), CastleGate2(), CastleGate1())
    CastleCorners(CornerSize)
    Choose(
      { CastleMaybe(CastlePart1(8)) CastleMaybe(CastlePart2(8)) CastleMaybe(CastlePart3(6)) },
      { CastleMaybe(CastlePart1(6)) CastleMaybe(CastlePart2(6)) CastleMaybe(CastlePart3(4)) }
    )
    Connector()
    Position(MIDDLE, {1 1}, FloodFill(And(AnyFloor(), Not AnyDoor()), Set("castle_outside")))
    Filter(And(Or(AnyFloor(), AnyDoor()), Not On("castle_outside")), Set("castle_inside", "stone_floor"))
    Place({1 1}, Set("inside_furniture"), 8, And(Not AnyDoor(), On("castle_inside")))
    Place({1 1}, Set("outside_furniture"), 8, On("castle_outside"))
    Border(BOTTOM, 2, Inside(BOTTOM, 1,
        Position(MIDDLE, {1 1}, Set("clear_middle", "up_stairs0", "stairs"))))
    Place({1 1}, Set("clear_middle", "down_stairs0", "stairs"), 1, On("castle_corner"))
    Place({2 2}, Set("shop0"), 1, And(On("castle_inside"), Not On("stairs")))
  })
}
End

"castle" {
  Choose(Castle(2), Castle(3))
  Filter(AnyFloor(), SetFront("clear_furniture"))
}

Def CastleEmpty(CornerSize) {
  Inside(1, {
    Building("castle_wall", "floor")
    Choose(CastleGate3(), CastleGate2(), CastleGate1())
    CastleCornersOpen(CornerSize)
    Position(MIDDLE, {1 1}, FloodFill(And(AnyFloor(), Not AnyDoor()), Set("stone_floor")))
    Border(BOTTOM, 2, Inside(BOTTOM, 1,
        Position(MIDDLE, {1 1}, Set("clear_middle", "up_stairs0", "stairs"))))
    Place({1 1} Set("clear_middle", "down_stairs0", "stairs") 1 On("castle_corner"))
    SetFront("clear_furniture")
  })
}
End

"castle_empty" Choose(CastleEmpty(2), CastleEmpty(3))

Def AdoxieFeetEntry() {
  Building("castle_wall", "stone_floor")
  Border(BOTTOM, 2,
    Border(TOP, 1,
      Position(
        MIDDLE,
        {3 1},
        {
          Reset("stone_floor")
          Margin(LEFT, 1,
            Set("adoxie_right_foot", "no_corpse"),
            Border(RIGHT, 1,
              Set("adoxie_left_foot", "no_corpse"))
          )
        }
      )
    )
  )
  Border(BOTTOM, 1,
    Position(MIDDLE, {1 1}, Reset("stone_floor", "iron_door")))
  Inside(TOP, 1,
    Border(TOP, 1,
      Position(MIDDLE, {1 1}, Set("down_stairs0", "no_corpse")))
  )
  Inside(1, Place({1 1}, Set("corpse"), {2 4}, Not On("no_corpse")))
}
End

"adoxie_feet_entry" AdoxieFeetEntry()

Def AdoxieFeetUnderRoom(EntrancePos)
{
  Reset("floor", "stockpile", "adoxie_feet_trigger")
  Border(-1, Set("no_dig"))
  Inside(-1, Position(EntrancePos, {1 1}, Remove("no_dig", "rock")))
}
End

Def AdoxieFeetUnder() {
  Set("rock")
  Inside(1, {
    Position(TOP_CENTER, {3 3}, AdoxieFeetUnderRoom(BOTTOM_CENTER))
    Position(RIGHT_CENTER,  {3 3}, AdoxieFeetUnderRoom(LEFT_CENTER))
    Position(LEFT_CENTER, {3 3}, AdoxieFeetUnderRoom(RIGHT_CENTER))
    Position(BOTTOM_CENTER,  {1 1}, Reset("floor", "up_stairs0"))
  })
  Connector()
}
End

"adoxie_feet_under" AdoxieFeetUnder()

Def CastleUpStairs() {
  Set("floor")
  Position(
    MIDDLE_V,
    {9 1}
    {
      Building("castle_wall", "stone_floor")
      Inside(1, Set("no_territory"))
      Inside(TOP, 4, Border(LEFT, 3, Border(RIGHT, 1, Filter(YMod(2, 0), Set("castle_wall")))))
      Inside(TOP, 4, Border(RIGHT, 3, Border(LEFT, 1, Filter(YMod(2, 0), Set("castle_wall")))))
    } 
  )
  Border(BOTTOM, 2, Inside(BOTTOM, 1,
     Position(MIDDLE, {1 1}, Set("clear_middle", "down_stairs0"))))
  Border(TOP, 3, Inside(TOP, 2,
     Position(MIDDLE, {1 1}, Set("clear_middle", "throne"))))
}
End

"castle_up_stairs" CastleUpStairs()

Def DoubleRoom() {
  Building("castle_wall", "wood_floor")
  Inside(1, SplitV(0.6,
    Margin(BOTTOM, 1,
      {
        Set("castle_wall")
        Place({1 1} Set("wood_door"))
      },
      {
        Set("first_room")
        Border(-1, Set("no_dig"))
      }
    ),
    Set("second_room")
  ))
}
End

Def GuardPostBase() {
  Position(
    position = MIDDLE,
    size = {5 7},
    generator = {
      Inside(-1, Set("main_building"))
      DoubleRoom()
    }
  )
  Place(
    minSize = {4 4}
    maxSize = {6 6}
    generator = Building("wood_wall", "floor")
    count = 1
    minSpacing = 1
    predicate = Not On("main_building")
  )
}
End

Def GuardPost() {
  GuardPostBase()
  Place (
    ({1 1} Set("up_stairs0") 1 And(On("first_room"), AnyFloor())),
    ({1 1} Set("dining_table") 1 And(On("first_room"), AnyFloor())),
    ({1 1} Set("torch") 1 And(On("first_room"), AnyFloor()))
  )
  Connector()
}
End

Def GuardPostFloor2() {
  Building("castle_wall", "wood_floor")
  Place (
    ({1 1} Set("down_stairs0") 1 FurnitureLoc()),
    ({1 1} Set("up_stairs0") 1 FurnitureLoc()),
    ({1 1} Set("armor_chest") {3 6} FurnitureLoc()),
    ({1 1} Set("bed") 2 FurnitureLoc()),
    ({1 1} Set("torch") 1 FurnitureLoc())
  )
}
End

Def GuardPostFloor3() {
  Building("wood_wall", "wood_floor")
  Place (
    ({1 1} Set("down_stairs0") 1 FurnitureLoc()),
    ({1 1} Set("pamphlet_chest") {2 4} FurnitureLoc())
  )
}
End

"guard_post" GuardPost()
"guard_post_floor2" GuardPostFloor2()
"guard_post_floor3" GuardPostFloor3()

Def Blacksmith() {
  Margin(1, Set("clear_middle", "floor"), DoubleRoom())
  Connector()
  Place (
    ({1 1} Set("forge") 3 And(On("second_room"), FurnitureLoc())),
    ({1 1} Set("down_stairs0") 1 And(On("second_room"), FurnitureLoc())),
    ({1 1} Set("dining_table") 2 And(On("first_room"), FurnitureLoc())),
    ({1 1} Set("bed") 3 And(On("first_room"), FurnitureLoc())),
    ({1 1} Set("torch") 1 And(On("first_room"), FurnitureLoc()))
  )
}
End

"blacksmith" Blacksmith()

Def BlacksmithCellar() {
  Building("wood_wall", "wood_floor")
  Place (
    ({1 1} Set("up_stairs0") 1 FurnitureLoc()),
    ({1 1} Set("blacksmith_chest") 3 FurnitureLoc()),
  )
}
End

"blacksmith_cellar" BlacksmithCellar()

Def CottageCellar() {
  Building("wood_wall", "wood_floor")
  Place (
    ({1 1} Set("up_stairs0") 1 FurnitureLoc()),
    ({1 1} Set("knife_chest") 1 FurnitureLoc()),
    ({1 1} Set("pamphlet_chest") {2 4} FurnitureLoc())
  )
}
End

"cottage_cellar" CottageCellar()

Def DungeonContent()
  Place (
    (
      size = {1 1}
      generator = Set("monster")
      count = 4
      predicate = On("room_floor")
    ),
    ({1 1} Set("up_stairs0") 1 On("room_floor")),
    ({1 1} Set("down_stairs0") 1 On("room_floor")),
    ({1 1} Set("up_stairs1") 1 On("room_floor")),
    ({1 1} Set("down_stairs1") 1 On("room_floor")),
    ({1 1} Set("inside_furniture") 10 On("room_floor"))
  )
End

Def Corners(Generator, Size) {
  Border(TOP, Size, {
    Border(LEFT, Size, Generator)
    Border(RIGHT, Size, Generator)
  })
  Border(BOTTOM, Size, {
    Border(LEFT, Size, Generator)
    Border(RIGHT, Size, Generator)
  })
}
End

Def Room() {
  Reset("floor", "room_floor")
  Margin(-1,
    Set("room_wall"),
    Corners(Set("no_dig"), 1)
  )
}
End

Def DungeonRooms()
  Inside(1,
    Place(
      minSize = {2 2}
      maxSize = {6 6}
      generator = Room()
      count = {7 11}
      minSpacing = 1
    )
  )
End

Def Dungeon1() {
  Set("rock")
  DungeonRooms()
  Connector()
  DungeonContent()
}
End

Def Dungeon2() {
  Set("rock")
  CellularAutomaton(Reset("floor", "room_floor"), 0.55)
  Connect(On("floor"),
    5, On("rock"), Reset("floor")
  )
  DungeonContent()
}
End

Def Caverns(Generator)
  Place(
    generator = CellularAutomaton(Generator, 0.55)
    count = {2 6}
    minSize = {10 10}
    maxSize = {14 14}
  )
End

Def Dungeon3() {
  Set("rock")
  Caverns(Reset("floor"))
  DungeonRooms()
  Connector()
  DungeonContent()
}
End

Def Dungeon4(WaterType) {
  Set("rock")
  Caverns(Reset("floor"))
  DungeonRooms()
  Caverns(Reset(WaterType))
  Connector()
  DungeonContent()
}
End

Def AdoxieTemple() {
  Set("rock")
  SplitH(0.5,
    Inside(1, Place(
      minSize = {2 2}
      maxSize = {6 6}
      generator = {
        Room()
        Position(MIDDLE, {1, 1}, Set("clear_middle", "up_stairs0"))
      }
      count = 1
      minSpacing = 1
    )),
    {
      CellularAutomaton(Set("lava"), 0.55)
      Place( 
        {7 7}
        {
          Inside(1, {
            Reset("floor", "temple")
            Corners(Set("castle_wall"), 1)
            Position(MIDDLE, {1 1}, Set("clear_middle", "down_stairs0"))
          })
          Set("no_dig")
          Position(MIDDLE_V, {1 1}, Remove("no_dig"))
          Position(MIDDLE_H, {1 1}, Remove("no_dig"))
        }
        1
        On("lava")
      )
    }
  )
  Connector()
  Filter(Not On("temple"), Set("no_territory"))
}
End

"adoxie_temple" AdoxieTemple()
"dungeon1" Dungeon1()
"dungeon2" Dungeon2()
"dungeon3" Dungeon3()
"dungeon4" Dungeon4("water")
"dungeon"
  Choose(
    Dungeon1(),
    Dungeon2(),
    Dungeon3(),
    Dungeon4("lava"),
    Dungeon4("water")
  )

Def ZLevelLakes(Type) {
  Set("hard_rock")
  CellularAutomaton(Reset(Type), 0.55)
  Inside(15, Place({1 1} Reset("floor", "up_stairs0") 1 On("hard_rock")))
  Filter(On(Type), Set("set_territory"))
}
End

"z_level_lava" ZLevelLakes("lava")
"z_level_water" ZLevelLakes("water")

Def ZLevelBase(Type) {
  Set("hard_rock")
  Position(MIDDLE, {1, 1}, {
    Border(-35, Set("resources"))
    Reset("floor", "up_stairs0")
  })
  Place(
     (none, CellularAutomaton(Reset(Type), 0.55), {0 10}, Not On("up_stairs0"), {5 5}, {20 20}),
     (none, CellularAutomaton(Reset("floor"), 0.55), {2 5}, Not On("up_stairs0"), {5 5}, {20 20})
  )
}
End
Def ZLevelFull(Type) {
  ZLevelBase(Type)
  Maybe(0.25, Place({6 6},
    Margin(1, Set(Type), { Reset("hard_rock") Inside(1, Set("ada_chest"))}), 1, On(Type)))
  Maybe(0.15, Place({20 15}, {
    Place(none, Reset("floor"), {2 5}, True, {2 2}, {5 5}, 1)
    Place({1 1}, Set("corpse"), {1 4}, On("floor"))
    Connector()
  }, 1, On("hard_rock")))
}
End

"z_level_full" Choose(ZLevelFull("water"), ZLevelFull("lava"))

Def MoveDown(Cnt, Generator)
  Inside(BOTTOM, -Cnt, Inside(TOP, Cnt, Generator))
End

Def ZLevelCastleLeft(Type) {
  Reset("hard_rock")
  Margin(LEFT, 6,
      CellularAutomaton(Reset(Type, "castle_moat"), 0.85),
      {
        Position(LEFT_CENTER, {1 2}, MoveDown(20, {
            Border(LEFT, -5, Set(Type))
            Set("iron_gate_blocking")
            Border(RIGHT, -10, Inside(LEFT, 2, Inside(-2, {
                Reset("floor", "castle_inside")
                Position(RIGHT_CENTER, {1 1}, Set("swarmer_chest"))
            })))
        }))
      }
  )
}
End

Def ZLevelCastle(Type) {
  ZLevelBase(Type)
  SplitH(0.6, {}, ZLevelCastleLeft(Type))
  Filter(Not On("castle_inside"), Set("no_territory"))
}
End

"z_level_castle" ZLevelCastle("lava")
