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"), On("underground_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, Or(On("water"), On("underground_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()

"stable" {
  Place(
    (size = {4 7}
    generator = {
      Building("wood_wall", "mud_floor")
      Corners(Set("corner"), 1)
      Place(1,
        ({1 2}, Reset("mud_floor", "wood_gate"), 1, And(On("wood_wall"), Not On("corner")))
        ({2 1}, Reset("mud_floor", "wood_gate"), 1, And(On("wood_wall"), Not On("corner")))
      )
      Place({1 1}, Set("haypile"), {3 6} And(Not On("wood_wall"), Not On("wood_gate")))
    }
    count = 1
    minSpacing = 2
  ),
  (size = {5 5}
  generator = {
    Building("castle_wall", "floor")
    Corners(Set("corner"), 1)
    Place({1 1}, Reset("wood_door", "floor"), 1, And(On("castle_wall"), Not On("corner")))
    Place(
      ({1 1}, Set("bed"), {3 6} And(Not On("castle_wall"), Not NextTo(On("wood_door")))),
      ({1 1}, Set("dining_table"), 1 And(Not On("castle_wall"), Not NextTo(On("wood_door"))))
    )
  }
  count = 1
  minSpacing = 2
  )
  )
}

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")
    Inside(TOP, 5, Inside(BOTTOM, 5,
        Filter(And(YMod(3, 0), On("castle_wall")), {Remove("castle_wall") Set("archer_wall")})))
    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 ZLevelCastle2(Type) {
  ZLevelMiniFeatures(Type)
#Place({1 1} Inside(-10, CellularAutomaton({Remove("hard_rock") Set("floor")}, 0.65)) 1 True)
  Inside(6, SplitH(0.6, {}, Place({25 15} {
    Choose(Castle(2), Castle(3))
    Remove("up_stairs0")
  } 1 And())))
  Filter(On("iron_gate"), Inside(-5, Filter(And(Not On("castle_wall"), On("hard_rock")), Reset("floor"))))
  Filter(Or(On("castle_wall"), On("archer_wall")), Set("no_dig")) 
  Connector()
  Place({5 5}, Border(TOP, 1, Set("weapon_rack", "black_dragon_weapon")), 1,
      And(Not AnyDoor(), On("castle_inside")))
  Place({1 1}, Set("blacksmith_chest"), 3, On("castle_outside"))
  Filter(Not On("castle_inside"), Set("no_territory"))
  Remove("shop0")
}
End

"z_level_castle2" ZLevelCastle2("lava")

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 AdoxieFeetUnderRemains(EntrancePos)
{
  Reset("stone_floor", "adoxie_feet_trigger")
  Border(-1, Set("no_dig", "stone_floor","castle_wall"))
  Inside(-1, Position(EntrancePos, {1 1}, Remove("no_dig", "rock")))
  Position(MIDDLE, {1 1}, Set("prophet_remains"))
}
End

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

Def AdoxieFeetUnder() {
  Set("rock")
  Inside(2, {
    Position(TOP_CENTER, {3 3}, AdoxieFeetUnderRemains(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 AdoxieStatueUnderLoot(EntrancePos)
{
  Reset("stone_floor")
  Border(-1, Set("no_dig"))
  Inside(-1, Position(EntrancePos, {1 1}, Remove("no_dig", "rock")))
  Position(TOP_STRETCHED, {1 1}, Set("chest"))
  Position(BOTTOM_STRETCHED, {1 1}, Set("chest"))
  Position(BOTTOM_RIGHT, {1 1}, {Remove("chest") Set("scroll_chest")})
  Position(RIGHT_CENTER, {1 1}, Set("trap"))
}
End

Def AdoxieStatueUnder() {
  Set("rock")
  Inside(2, {
    Position(RIGHT_CENTER, {3 3}, AdoxieStatueUnderLoot(LEFT_CENTER))
    Position(BOTTOM_CENTER,  {1 1}, Reset("floor", "up_stairs0"))
  })
  Connector()
}
End

"adoxie_statue_under" AdoxieStatueUnder()

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 AdventurerStable() {
  Building("wood_wall", "wood_floor")
  Corners(Set("no_door"), 1)
  Place({1 1} Reset("wood_floor", "wood_door") 1 And(On("wood_wall"), Not On("no_door")))
  Filter(On("wood_floor"), Set("stable"))
  Place (
    ({1 1} Set("haypile") 1 FurnitureLoc()),
    ({1 1} Set("torch") 1 FurnitureLoc()),
  )
}
End

Def AdventurerHut() {
  Building("wood_wall", "wood_floor")
  Corners(Set("no_door"), 1)
  Place({1 1} Reset("wood_floor", "wood_door") 1 And(On("wood_wall"), Not On("no_door")))
  Place (
    ({1 1} Set("dining_table") 1 FurnitureLoc()),
    ({1 1} Set("bed") 1 FurnitureLoc()),
    ({1 1} Set("torch") 1 FurnitureLoc()),
    ({1 1} Set("adventurer_chest") 1 FurnitureLoc()),
  )
}
End

"adventurer_house" {
  Place(
    (size = {5 5} generator = AdventurerHut() minSpacing = 1),
    (size = {5 4} generator = AdventurerStable() minSpacing = 1)
  )
}

"adoxie_adventurer" {
    CellularAutomaton(Set("clear_middle", "connect"), 0.75)
    Inside(2, CellularAutomaton(Set("lava"), 0.75))
}

"special_tree" {
  Inside(1, Place({1 1} Set("special_tree")))
}

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("underground_water")
"dungeon"
  Choose(
    Dungeon1(),
    Dungeon2(),
    Dungeon3(),
    Dungeon4("lava"),
    Dungeon4("underground_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("underground_water")

Def ZLevelMostlyFull(WaterType) {
  Set("hard_rock", "resources")
  Inside(5,
    Place(
      (none, CellularAutomaton(Reset(WaterType), 0.55), {0 10}, True, {5 5}, {20 20}),
      (none, CellularAutomaton(Reset("floor"), 0.55), {2 5}, True, {5 5}, {20 20})
    )
  )
}
End

Def ZLevelCaverns(FloorType, Amount) {
  Set("hard_rock", "resources")
  Inside(5, CellularAutomaton(Reset(FloorType), Amount))
}
End

"z_level_caverns" ZLevelCaverns("floor", 0.45)
"z_level_flooded_caverns" ZLevelCaverns("underground_water", 0.55)

Def MiniWorkshop() {
  Reset("floor")
  Position(MIDDLE, {2 2}, Set("workshop"))
  Place(
    ({1 1}, Set("gnome_corpse"), {2 5}, Not On("workshop")),
    ({1 1}, Set("automaton_parts"), {2 5}, Not On("workshop"))
  )
}
End

Def MiniThrone()
{
  Reset("floor")
  Position(TOP_CENTER, {1 1}, Set("broken_throne"))
  Border(LEFT, 2, Border(RIGHT, 1, Filter(YMod(2, 0), Reset("hard_rock"))))
  Border(RIGHT, 2, Border(LEFT, 1, Filter(YMod(2, 0), Reset("hard_rock"))))
  Border(-1, Set("no_dig"))
  Position(BOTTOM_CENTER, {1 1}, Border(BOTTOM, -1, Remove("no_dig")))
}
End

Def ZLevelMiniFeatures(WaterType) {
  ZLevelMostlyFull(WaterType)
  Inside(5, Place(2,
    ({6 6}, MiniWorkshop(), 1, On("hard_rock")),
    ({7 10}, MiniThrone(), 1, On("hard_rock"))
    ({12 12}, MiniGhostSpawner(), 1, On("hard_rock")),
    ({12 12}, EnchantedPool(), 1, On("hard_rock")),
    ({7 7}, MiniBrokenPrison(), 1, On("hard_rock")),
    ({7 7}, MiniPrison(), 1, On("hard_rock")),
    ({7 7}, ColumnRoom(), 1, On("hard_rock")),
    ({5 5}, MiniGargoyleRoom(), 1, On("hard_rock")),
    ({15 15}, MiniDungeon(), 1, On("hard_rock")),
    ({15 15}, MiniAntNest(), 1, On("hard_rock")),
    ({4 4}, { Border(-1, Reset(WaterType)) Reset("hard_rock") Inside(1, Set("ada_chest"))}, 1, On(WaterType)),
    ({10 10}, {
      CellularAutomaton(Reset(WaterType), 0.85)
      Inside(3, FourCorners(Reset("hard_rock")))
    }, 1, On("hard_rock"))
  ))
  Place({1 1}, Set("bat"), {1 4}, On("floor"))
}
End

"z_level_minifeatures" ZLevelMiniFeatures("underground_water")

Def ZLevelBase(WaterType)
  Choose(ZLevelMiniFeatures(WaterType), ZLevelCaverns("floor", 0.45), ZLevelCaverns("underground_water", 0.55))
End

Def MiniGargoyleRoom() {
  Reset("floor")
  FourCorners(Set("no_dig", "gargoyle"))
}
End

Def MiniGhostSpawner() {
  CellularAutomaton(Reset("floor"), 0.85)
  Inside(2, CellularAutomaton(Set("fog"), 0.85))
  Position(MIDDLE, {1 1}, Reset("ghost_spawn", "fog"))
}
End

Def EnchantedPool() {
  CellularAutomaton(Reset("floor"), 0.85)
  Inside(3, CellularAutomaton(Reset("enchanted_water"), 0.85))
  Maybe(0.2, Place({1 1}, Set("enchanted_workshop"), 1, And(Not On("enchanted_water"), NextTo(On("enchanted_water")))))
  Maybe(0.2, Place({1 1}, Set("enchanted_lab"), 1, And(Not On("enchanted_water"), NextTo(On("enchanted_water")))))
}
End

Def MiniAntNest() {
  Place(none, {
    Reset("floor")
    Place({1, 1}, Set("ant_worker"), 1, True)
  }, 7, True, {1 1}, {3 3})
  Connector()
}
End

Def MiniDungeon() {
  Place(none, Reset("floor"), {2 5}, True, {2 2}, {5 5}, 1)
  Place({1 1}, Set("corpse"), {1 4}, On("floor"))
}
End

Def MiniBrokenPrison() {
  Reset("floor")
  Border(-1, Set("no_dig"))
  Border(TOP, 3, {
    Border(BOTTOM, 1, Filter(Chance(0.8), Set("prison_bars")))
    Border(TOP, -1, Remove("no_dig"))
  })
  Inside(TOP, 4, Place({1 1}, Set("corpse"), {1 4}, On("floor")))
}
End

Def MiniPrison() {
  Reset("floor")
  Border(-1, Set("no_dig"))
  Border(TOP, 3, {
    Border(BOTTOM, 1, Set("prison_bars"))
    Border(TOP, -1, Remove("no_dig"))
  })
  Place({1 1}, Reset("floor", "prison_door"), 1, On("prison_bars"))
  Inside(TOP, 4, Place({1 1}, Set("elf_archer"), {1 4}, On("floor")))
}
End

Def YColumns() Filter(YMod(2, 0), Set("hard_rock")) End
Def XColumns() Filter(XMod(2, 0), Set("hard_rock")) End

Def ColumnRoom() {
  Reset("floor")
  Inside(1, {
    Margin(RIGHT, 1, YColumns(), {})
    Margin(LEFT, 1, YColumns(), {})
    Margin(TOP, 1, XColumns(), {})
    Margin(BOTTOM, 1, XColumns(), {})
  })
  Place({1, 1}, Set("bat"), {3 6}, On("floor"))
}
End

Def FourCorners(Corner) {
  Position(TOP_LEFT, {1 1}, Corner)
  Position(BOTTOM_LEFT, {1 1}, Corner)
  Position(TOP_RIGHT, {1 1}, Corner)
  Position(BOTTOM_RIGHT, {1 1}, Corner)
}
End

"z_level_full" {
  Set("set_territory") # Even though its an empty level, some code will crash if territory is empty
  Choose(ZLevelMostlyFull("underground_water"), ZLevelMostlyFull("lava"))
}

"z_level_full_only_water" {
  Set("set_territory") # Even though its an empty level, some code will crash if territory is empty
  ZLevelMostlyFull("underground_water")
  Maybe(0.5, Place({12 12}, EnchantedPool(), 1, On("hard_rock")))
}

"z_level_vault" {
  Choose(ZLevelBase("underground_water"), ZLevelBase("lava"))
  Inside(5, Place({4 7}, {
    Reset("floor", "set_territory")
    Margin(TOP, 1, Set("workshop"),
      Place(
        ({1 1}, Set("bed"), {1 4}, And()),
        ({1 1}, Set("torch"), 1, And())
    ))
  }, 1, On("hard_rock")))
  Connector()
  Filter(Not On("set_territory"), Set("no_territory"))
}

"z_level_cave" {
  Choose(ZLevelBase("underground_water"), ZLevelBase("lava"))
  Inside(5, Place({10 10}, CellularAutomaton(Reset("floor", "set_territory"), 0.85), 1, On("hard_rock")))
  Connector()
  Filter(Not On("set_territory"), Set("no_territory"))
}

"z_level_cave_only_water" {
  Choose(ZLevelBase("underground_water"))
  Inside(5, Place({10 10}, CellularAutomaton(Reset("floor", "set_territory"), 0.85), 1, On("hard_rock")))
  Connector()
  Filter(Not On("set_territory"), Set("no_territory"))
}

"z_level_dungeon" {
  Choose(ZLevelBase("underground_water"), {
    ZLevelBase("lava")
    Maybe(0.25, Place({1 1},
      {
        Inside(-1, Filter(Not On("lava"), Reset("floor")))
        Position(MIDDLE, {1 1}, Set("lava_forge"))
      }
      1, And(Not On("lava"), NextTo(On("lava")))))
  })
  Inside(5, Place({15 12}, {
    Place(none, Reset("floor", "set_territory"), {3 6}, True, {2 2}, {5 5}, 1)
  }, 1, On("hard_rock")))
  Connector()
  Place({1 1}, Choose(Set("bed"), Set("chest")), {4 7}, On("set_territory"))
  Filter(And(
    On("floor"),
    NextTo(On("set_territory")),
    Not NextTo(On("wood_door")),
    Or(
      And(Translate({0 1}, On("hard_rock")), Translate({0 -1}, On("hard_rock"))),
      And(Translate({1 0}, On("hard_rock")), Translate({-1 0}, On("hard_rock")))
    )
  ), Set("wood_door"))
  Filter(Not On("set_territory"), Set("no_territory"))
}

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) {
  ZLevelMiniFeatures(Type)
  Connector()
  SplitH(0.6, {}, ZLevelCastleLeft(Type))
  Filter(Not On("castle_inside"), Set("no_territory"))
}
End

"z_level_castle" ZLevelCastle("lava")

Def LavaCave() {
  Set("hard_rock")
  CellularAutomaton(Reset("lava"), 0.55)
  CellularAutomaton(Reset("floor"), 0.45)
  Inside(2, SplitH(0.3, SplitV(0.3,
      Place({4 4}, {Reset("stone_floor") Inside(1, Set("chest"))}, 1),
      {}), {}))
  Inside(2, SplitH(0.7, {}, SplitV(0.7, {},
    Place({1 1}, {Inside(-1, {Remove("hard_rock", "lava") Set("floor")}) Set("up_stairs0")}, 1, On("hard_rock")))))
  Connect(Or(On("up_stairs0"), On("chest")), 30, Not On("floor"), {Set("floor") Remove("lava", "hard_rock")})
  Filter(Not On("stone_floor"), Set("no_territory"))
}
End

"lava_cave" LavaCave()

Def CoffinRoom(WHAT) {
  Border(LEFT, 2, Set("no_dig"))
  Inside(1, Reset("floor", WHAT))
  Choose(
    Position(RIGHT_CENTER, {1 1}, Reset("floor"))
  )
}
End

Def CoffinRoomDoor() {
  Border(RIGHT, 6, Set("no_dig"))
  Border(LEFT, 3, Position(MIDDLE, {1 1}, Reset("floor", "loot_coffin")))
  Position(MIDDLE, {3 1}, {
    Margin(LEFT, 2, Reset("floor", "hidden_door"), Reset("floor", "zombie_chest"))
  })
  Choose(
    Position(LEFT_CENTER, {1 1}, Reset("floor"))
  )
  Set("no_territory")
}
End

Def ZombieCrypt() {
  Reset("hard_rock")
  Inside(2, Place(
      ({3 3}, CoffinRoom("loot_coffin"), 9),
      ({3 3}, CoffinRoom("up_stairs0"), 1),
      ({7 5}, CoffinRoomDoor(), 1)
  ))
  Connector()
  Filter(On("hard_rock"), Reset("castle_wall"))
}
End

"zombie_crypt" ZombieCrypt()

Def KrakenPrison() {
  CellularAutomaton(Reset("underground_water"), 0.65)
  Position(MIDDLE, {6 6}, {Reset("prison") Border(1, Reset("floor", "castle_wall"))})
  Place(({1 1} Reset("kraken_water") 10 On("underground_water")))
}
End

Def KrakenZLevel() {
  Set("hard_rock", "resources")
  Inside(10, Place({25 25}, KrakenPrison(), 1))
  Filter(On("prison"), Set("set_territory"))
  Filter(Not On("prison"), Set("no_territory"))
}
End

"kraken_z_level" KrakenZLevel()

"crops" {
  CellularAutomaton(Set("crops"), 0.9)
  Place(({1 1} Set("scarecrow") 1 On("crops")))
}

"hydra" {
  Inside(5, {
      CellularAutomaton(Reset("water"), 0.65)
      Set("set_territory")
  })
  CellularAutomaton(Set("fog"), 0.65)
}

"fog_ruins" {
  Position(MIDDLE, {5 5}, {
    Border(1, Filter(Chance(0.7), Set("ruin_wall")))
    Set("set_territory")
  })
  CellularAutomaton(Set("fog"), 0.65)
}

"shelob" {
  CellularAutomaton(Reset("floor", "spider_web"), 0.65)
  Set("connect")
}

"balrog_z_level" {
  ZLevelMiniFeatures("lava")
#Place({1 1} Inside(-10, CellularAutomaton({Remove("hard_rock") Set("floor")}, 0.65)) 1 On("up_stairs0"))
  Inside(6, SplitH(0.6, {}, Place({9 18} {
    Border(-1, Reset("hard_rock"))
    Inside(-1, Inside(TOP, 2, Set("no_dig")))
    Reset("floor", "inside")
    Inside(BOTTOM, 2, Inside(TOP, 2, Border(LEFT, 3, Border(RIGHT, 1, Filter(YMod(2, 0), Set("hard_rock"))))))
    Inside(BOTTOM, 2, Inside(TOP, 2, Border(RIGHT, 3, Border(LEFT, 1, Filter(YMod(2, 0), Set("hard_rock"))))))
    Inside(TOP, 13, Place({1 1} Set("wizard_corpse") 1 Not On("hard_rock")))
  } 1 And())))
  Connector()
  Filter(Not On("inside"), Set("no_territory"))
}

Def Connections(Name, Pred)
{
  Inside(TOP, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 -1}, On("set_" + Name))), Set("map_" + Name + "_n")))
  Inside(BOTTOM, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 1}, On("set_" + Name))), Set("map_" + Name + "_s")))
  Inside(LEFT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({-1 0}, On("set_" + Name))), Set("map_" + Name + "_w")))
  Inside(RIGHT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({1 0}, On("set_" + Name))), Set("map_" + Name + "_e")))
  Inside(TOP, 1, Inside(LEFT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 -1}, On("set_" + Name)), Translate({-1 0}, On("set_" + Name))),
      Set("map_" + Name + "_nw"))))
  Inside(TOP, 1, Inside(RIGHT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 -1}, On("set_" + Name)), Translate({1 0}, On("set_" + Name))),
      Set("map_" + Name + "_ne"))))
  Inside(BOTTOM, 1, Inside(LEFT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 1}, On("set_" + Name)), Translate({-1 0}, On("set_" + Name))),
      Set("map_" + Name + "_sw"))))
  Inside(BOTTOM, 1, Inside(RIGHT, 1, Filter(And(Pred, Not On("set_" + Name), Translate({0 1}, On("set_" + Name)), Translate({1 0}, On("set_" + Name))),
      Set("map_" + Name + "_se"))))
}
End

Def BigMountain()
  And(On("set_mountains"), Not On("big_mountain"))
End

Def WorldMapFeatures() {
  Inside(1, Filter(And(Chance(0.1), BigMountain(), Translate({0 -1}, BigMountain()),
      Translate({-1 0}, BigMountain()), Translate({-1 -1}, BigMountain())),
      Set("big_mountain")))
  Filter(On("big_mountain"), Choose(Set("map_mountains_large"), Set("map_mountains_large2"),
      Set("map_mountains_large3"), Set("map_mountains_large4")))
  Filter(On("set_mountains"), {Set("MOUNTAIN") {Set("map_mountains_bg1") Choose(Set("map_mountains1"),
      Set("map_mountains2"), Set("map_mountains3"), Set("map_mountains4"), Set("map_mountains5"))}})
  Filter(On("set_mountains_snow"), {Set("MOUNTAIN") Choose(Set("map_mountains_snow1"), Set("map_mountains_snow2"),
      Set("map_mountains_snow3"), Set("map_mountains_snow4"), Set("map_mountains_snow5"))})
  Filter(On("set_water"), {Choose(0.7 Set("map_water1"), Set("map_water2"), Set("map_water3"), Set("map_water5"))})
  Filter(On("set_sand"), {Set("DESERT") Choose(0.7 Set("map_sand1"), Set("map_sand2"))})
  Filter(On("set_grass"), {Set("GRASSLAND") Choose(0.7 Set("map_grass1"), Set("map_grass2"), Set("map_grass3"))})
  Filter(On("set_snow"), {Set("SNOW") Choose(0.7 Set("map_snow1"), Set("map_snow2"))})
  Filter(On("set_swamp"), {Set("SWAMP") Choose(0.7 Set("map_swamp1"), Set("map_swamp2"), Set("map_swamp3"), Set("map_swamp4"))})
End

Def WorldMapConnections() {
  Connections("mountains", True)
  Connections("snow", Not On("set_mountains"))
  Connections("grass", Not Or(On("set_snow"), On("set_mountains")))
  Connections("swamp", Not Or(On("set_snow"), On("set_mountains"), On("set_grass")))
  Connections("sand", Not Or(On("set_grass"), On("set_snow"), On("set_mountains"), On("set_swamp")))
}
End

Def WorldMapTrees() {
  NoiseMap(0.85, {
    (0.0, 0.15, Filter(On("set_grass"), Set("set_tree")))
  })
  Filter(On("set_tree"), {Set("FOREST") Choose(Set("map_tree1"), Set("map_tree2"), Set("map_tree3"))})}
}
End

"world_map" {
  NoiseMap(0.65, {
    (0.8, 1.0, Reset("set_water"))
    (0.74, 0.8, Reset("set_sand"))
    (0.2, 0.74, Reset("set_grass"))
    (0.0, 0.2, Reset("set_mountains"))
    #(0.0, 0.02, Set("set_lava"))
  })
  #Position(MIDDLE, {1 1}, FloodFill(Or(On("sand"), On("grass"), On("water")), Set("save")))
  #Filter(Not On("save"), Reset("mountain"))
  #Border(1, Filter(Not On("mountain"), Fail))
  CellularAutomaton(Filter(Not On("set_mountains"), Reset("set_water")), 0.35)
  Inside(TOP, 18, Inside(BOTTOM, 18, CellularAutomaton(Set("water_area"), 0.75)))
  SplitV(0.5,
    Filter(And(Not On("water_area"), Or(On("set_water"), On("set_sand"))), Reset("set_snow")),
    Filter(And(Not On("water_area"), Or(On("set_water"), On("set_sand"))), Reset("set_sand"))
  )
  Filter(And(On("set_sand"), On("water_area")), Reset("set_swamp"))
  NoiseMap(0.65, {
    (0.0, 0.2, Filter(On("set_snow"), Set("set_mountains_snow")))
  })
  WorldMapFeatures()
  WorldMapConnections()
  WorldMapTrees()
}

"world_map_test" {
  NoiseMap(0.65, {
    (0.8, 1.0, Reset("set_water"))
    (0.74, 0.8, Reset("set_sand"))
    (0.2, 0.74, Reset("set_grass"))
    (0.0, 0.2, Reset("set_mountains"))
    #(0.0, 0.02, Set("set_lava"))
  })
  #Position(MIDDLE, {1 1}, FloodFill(Or(On("sand"), On("grass"), On("water")), Set("save")))
  #Filter(Not On("save"), Reset("mountain"))
  #Border(1, Filter(Not On("mountain"), Fail))
  CellularAutomaton(Filter(Not On("set_mountains"), Reset("set_water")), 0.35)
  SplitV(0.7, Filter(On("set_sand"), Reset("set_swamp")), Filter(On("set_water"), Reset("set_sand")))
  SplitV(0.3, Filter(Or(On("set_water"), On("set_sand")), Reset("set_snow")), {})
  NoiseMap(0.65, {
    (0.0, 0.2, Filter(On("set_snow"), Set("set_mountains_snow")))
  })
  CellularAutomaton(Set("continent"), 0.5)
  Filter(Not On("continent"), Reset("set_water"))
  WorldMapFeatures()
  WorldMapConnections()
  WorldMapTrees()
}