// === BUILD PLAN ===
// Style: Ottoman hammam, cross-plan: camekan (domed hall + gallery ring) -> passage -> sicaklik (ribbed dome)
// with two halvet (private cell) domes budding off the far side
// Footprint:
// camekan X20..34 Z30..44 outer (13x13 inside) dome R6, walls top y=20
// passage X34..38 Z35..39 vault y=15
// sicaklik X38..54 Z28..44 outer (15x15 inside) RIBBED dome R7, walls top y=19
// halvets X54..60 Z29..35 and X54..60 Z37..43 small domes R3, walls top y=15
// porch columned portico X22..32 Z26..30 with stepped muqarnas hood over the door
// Height: floorY=9 walkY=10; gallery walk y=16; dome apexes 27 (camekan) / 27 (sicaklik)
//
// GROUND FLOOR (schematic, 1 char ~ 1 block):
// .......ppppppppp..............................
// ......#####D#####.............................
// ......# camekan #====# sicaklik #==# h #
// ......# pool # # O navel O # #####
// ......# gallery #====# basins #==# h #
// ......########### ################ #####
// Legend: p portico, D door, O navel stone, h halvet cell, = passage
//
// SECTION (north-south through the two big rooms):
// .-'''-. .-'''-. <- domes on drums, ribs on the sicaklik one
// / \ / \
// | gallery | | navel |
// |___|_|___|________|____|____|
//
// MATERIALS PLAN:
// ground : terrain() sand/coarse_dirt pads at y=8 - WHY: flat pad, build never buried
// walls : gradientPalette sandstone->cut_sandstone->smooth_sandstone (noise .2) - WHY: fake AO on big blank walls
// relief : chiseled_sandstone pilasters + terracotta string band + stair cornice - WHY: wall_depth, kill the flat box
// domes : deepslate/andesite lead ramp; ribs cut_sandstone on the main dome - WHY: lead-vs-stone contrast
// interior: quartz marble mix + prismarine basins + dark_oak gallery - WHY: cool marble vs warm wood
// light : lanterns, star skylights of orange/yellow stained glass in each dome
// Rooms: camekan (octagonal pool, benches, carpets, gallery ring w/ staircase),
// sicaklik (raised octagonal navel stone, 4 niche basins, marble benches),
// halvets (private cells: basin + bench + lantern)
// STAIR PLAN: camekan walk 10 -> gallery walk 16 (D=6) -> staircase(32,41,10,16,"north"), 7 cells, width 2
// === END PLAN ===
var floorY = 9, walkY = 10, padY = 8;
// ---------- 1. TERRAIN (superpowers, flat pad under the whole building) ----------
terrain({ cx:40, cz:36, radius:38, baseY:padY, amp:3, scale:0.05, seed:77,
surface:[{block:'sand',weight:50},{block:'coarse_dirt',weight:25},{block:'grass_block',weight:15},{block:'sandstone',weight:10}],
sub:'sandstone', deep:'sandstone', depth:4,
pads:[{cx:40, cz:36, r:30, y:padY, falloff:7}] });
// ---------- palettes ----------
var stonePal = gradientPalette(floorY, 20, [
{block:'sandstone', from:0},
{block:'cut_sandstone', from:0.4},
{block:'smooth_sandstone', from:0.8}], {noise:0.2, seed:31});
var marble = noisePalette([{block:'quartz_block',weight:50},{block:'smooth_quartz',weight:35},{block:'quartz_bricks',weight:15}], {seed:5, freq:0.13});
// ---------- generic room builder ----------
// Builds shell + floor + SOLID ceiling deck, then (optionally) a drum + dome with a clean oculus.
function room(x1, z1, x2, z2, topY, floorBlock){
makeWalls(x1, floorY, z1, x2, topY, z2, stonePal);
fill(x1, floorY, z1, x2, floorY, z2, floorBlock);
fill(x1+1, walkY, z1+1, x2-1, topY, z2-1, 'air'); // interior bounds only (walls stay)
fill(x1, topY+1, z1, x2, topY+1, z2, 'smooth_sandstone'); // SOLID deck - no sky gaps
}
function domeOn(cx, cz, deckY, R, ribbed){
var dy, dx, dz, outerR, innerR, d2, ang, k, isRib, frac, jit, shell;
// drum ring, 2 courses
for (dy = 0; dy < 2; dy++)
for (dx = -R; dx <= R; dx++)
for (dz = -R; dz <= R; dz++){
d2 = dx*dx + dz*dz;
if (d2 <= R*R + R && d2 >= (R-1)*(R-1)) pb(cx+dx, deckY+1+dy, cz+dz, 'cut_sandstone');
}
var baseY = deckY + 3;
for (dy = 0; dy <= R; dy++){
outerR = Math.round(Math.sqrt(R*R - dy*dy));
innerR = Math.round(Math.sqrt(Math.max(0, (R-1)*(R-1) - dy*dy)));
for (dx = -outerR; dx <= outerR; dx++)
for (dz = -outerR; dz <= outerR; dz++){
d2 = dx*dx + dz*dz;
if (d2 <= outerR*outerR + outerR && !(d2 <= innerR*innerR)){
isRib = false;
if (ribbed && dy < R - 1){
ang = Math.atan2(dz, dx);
k = Math.abs(((ang + Math.PI) / (Math.PI/4)) % 1);
if (k < 0.15 || k > 0.85) isRib = true;
}
frac = dy / R;
jit = ((cx+dx)*5 + (cz+dz)*11 + dy) % 4;
shell = (frac + jit*0.04 < 0.4) ? 'deepslate' : ((frac + jit*0.04 < 0.8) ? 'andesite' : 'polished_andesite');
pb(cx+dx, baseY+dy, cz+dz, isRib ? 'cut_sandstone' : shell);
}
}
}
// hollow the dome + drum + punch a clean circular oculus through the deck (radius R-2)
var hr = R - 2;
for (dy = 0; dy < R; dy++){
innerR = Math.round(Math.sqrt(Math.max(0, (R-1)*(R-1) - dy*dy)));
for (dx = -innerR; dx <= innerR; dx++)
for (dz = -innerR; dz <= innerR; dz++)
if (dx*dx + dz*dz <= innerR*innerR) pb(cx+dx, baseY+dy, cz+dz, 'air');
}
for (dy = deckY; dy <= deckY + 2; dy++)
for (dx = -hr; dx <= hr; dx++)
for (dz = -hr; dz <= hr; dz++)
if (dx*dx + dz*dz <= hr*hr + 1) pb(cx+dx, dy, cz+dz, 'air');
// star skylight in the crown + hidden glowstone above it
var pts = [[0,0],[1,0],[-1,0],[0,1],[0,-1],[1,1],[-1,-1],[2,0],[0,2],[-2,0],[0,-2]];
var i, r2, yy;
for (i = 0; i < pts.length; i++){
r2 = Math.sqrt(pts[i][0]*pts[i][0] + pts[i][1]*pts[i][1]);
yy = baseY + Math.round(Math.sqrt(Math.max(0, R*R - r2*r2)));
pb(cx+pts[i][0], yy, cz+pts[i][1], (i % 3 === 0) ? 'orange_stained_glass' : 'yellow_stained_glass');
}
pb(cx, baseY + R + 1, cz, 'glowstone');
}
function pilasters(x1, z1, x2, z2, topY, step){
var x, z;
for (x = x1; x <= x2; x += step){
fill(x, floorY, z1, x, topY-1, z1, 'chiseled_sandstone');
fill(x, floorY, z2, x, topY-1, z2, 'chiseled_sandstone');
ps(x, topY, z1, 'cut_sandstone_slab[type=top]');
ps(x, topY, z2, 'cut_sandstone_slab[type=top]');
}
for (z = z1; z <= z2; z += step){
fill(x1, floorY, z, x1, topY-1, z, 'chiseled_sandstone');
fill(x2, floorY, z, x2, topY-1, z, 'chiseled_sandstone');
ps(x1, topY, z, 'cut_sandstone_slab[type=top]');
ps(x2, topY, z, 'cut_sandstone_slab[type=top]');
}
}
function bandRing(x1, z1, x2, z2, y, blockId){
var x, z;
for (x = x1; x <= x2; x++){ pb(x, y, z1, blockId); pb(x, y, z2, blockId); }
for (z = z1; z <= z2; z++){ pb(x1, y, z, blockId); pb(x2, y, z, blockId); }
}
function corniceRing(x1, z1, x2, z2, y){
var x, z;
for (x = x1; x <= x2; x++){ roofStair(x, y, z1-1, 'sandstone_stairs', 'south'); roofStair(x, y, z2+1, 'sandstone_stairs', 'north'); }
for (z = z1-1; z <= z2+1; z++){ roofStair(x1-1, y, z, 'sandstone_stairs', 'east'); roofStair(x2+1, y, z, 'sandstone_stairs', 'west'); }
}
// ---------- 2. ROOMS ----------
var topCam = 20, topSic = 19, topHal = 15, topPas = 14;
room(20, 30, 34, 44, topCam, 'smooth_sandstone'); // camekan
room(38, 28, 54, 44, topSic, 'smooth_sandstone'); // sicaklik
room(54, 29, 60, 35, topHal, 'polished_andesite'); // halvet north
room(54, 37, 60, 43, topHal, 'polished_andesite'); // halvet south
room(34, 35, 38, 39, topPas, 'polished_diorite'); // passage camekan-sicaklik
room(52, 32, 56, 34, topPas, 'polished_diorite'); // no-op link (kept solid, decorative buttress)
// doorways (1 wide x 2 tall, kept clear)
fill(34, walkY, 36, 34, walkY+2, 38, 'air');
fill(38, walkY, 36, 38, walkY+2, 38, 'air');
fill(54, walkY, 31, 54, walkY+2, 33, 'air');
fill(54, walkY, 39, 54, walkY+2, 41, 'air');
// ---------- 3. FACADE RELIEF ----------
pilasters(20, 30, 34, 44, topCam, 3);
pilasters(38, 28, 54, 44, topSic, 4);
bandRing(20, 30, 34, 44, 15, 'terracotta');
bandRing(38, 28, 54, 44, 15, 'terracotta');
corniceRing(20, 30, 34, 44, topCam + 1);
corniceRing(38, 28, 54, 44, topSic + 1);
corniceRing(54, 29, 60, 35, topHal + 1);
corniceRing(54, 37, 60, 43, topHal + 1);
// small arched windows high on the sicaklik walls
var wz;
for (wz = 31; wz <= 41; wz += 5){
ps(38, 16, wz, 'orange_stained_glass');
ps(54, 16, wz, 'orange_stained_glass');
pb(38, 17, wz, 'sandstone_slab[type=bottom]');
pb(54, 17, wz, 'sandstone_slab[type=bottom]');
}
// ---------- 4. DOMES ----------
domeOn(27, 37, topCam + 1, 6, false); // camekan dome
domeOn(46, 36, topSic + 1, 7, true); // sicaklik RIBBED dome
domeOn(57, 32, topHal + 1, 3, false); // halvet domes
domeOn(57, 40, topHal + 1, 3, false);
// passage barrel vault
var pv;
for (pv = 35; pv <= 37; pv++){
roofStair(35, topPas, pv, 'cut_sandstone_stairs', 'west');
roofStair(37, topPas, pv, 'cut_sandstone_stairs', 'east');
}
// ---------- 5. PORTICO + MUQARNAS PORTAL (north face of the camekan) ----------
var col;
for (col = 22; col <= 32; col += 4){
fill(col, floorY, 27, col, 15, 27, 'quartz_pillar[axis=y]');
pb(col, 16, 27, 'chiseled_quartz_block');
}
fill(21, 16, 26, 33, 16, 28, 'smooth_sandstone');
fill(21, 17, 26, 33, 17, 28, 'cut_sandstone');
corniceRing(22, 27, 32, 28, 17);
fill(21, padY+1, 27, 33, padY+1, 29, 'polished_diorite');
// door + stepped muqarnas hood above it
fill(26, walkY, 30, 28, walkY+2, 30, 'air');
ps(27, walkY, 30, 'dark_oak_door[facing=north,half=lower,hinge=left]');
ps(27, walkY+1, 30, 'dark_oak_door[facing=north,half=upper,hinge=left]');
var h;
for (h = 0; h < 4; h++){
var hy = walkY + 3 + h;
var half = 3 - h;
var hx;
for (hx = 27 - half; hx <= 27 + half; hx++) pb(hx, hy, 29, 'chiseled_sandstone');
roofStair(27 - half - 1, hy, 29, 'cut_sandstone_stairs', 'west');
roofStair(27 + half + 1, hy, 29, 'cut_sandstone_stairs', 'east');
}
pb(27, walkY + 7, 29, 'sandstone_wall');
pb(27, walkY + 8, 29, 'lantern[hanging=false]');
// ---------- 6. CAMEKAN INTERIOR ----------
fill(21, floorY, 31, 33, floorY, 43, marble);
fill(21, walkY, 31, 33, walkY+3, 31, 'smooth_quartz');
fill(21, walkY, 43, 33, walkY+3, 43, 'smooth_quartz');
fill(21, walkY, 31, 21, walkY+3, 43, 'smooth_quartz');
fill(33, walkY, 31, 33, walkY+3, 43, 'smooth_quartz');
// octagonal pool with a small jet
var px, pz, dman;
for (px = 24; px <= 30; px++)
for (pz = 34; pz <= 40; pz++){
dman = Math.abs(px-27) + Math.abs(pz-37);
if (dman <= 3) pb(px, floorY, pz, 'water');
else if (dman === 4) pb(px, floorY, pz, 'polished_diorite');
}
pb(27, floorY+1, 37, 'water');
pb(27, floorY, 37, 'prismarine_bricks');
// benches + carpets + props
var bz2;
for (bz2 = 33; bz2 <= 41; bz2 += 2){
chairStair(22, walkY, bz2, 'dark_oak_stairs', 'east');
chairStair(32, walkY, bz2, 'dark_oak_stairs', 'west');
}
var cxx, czz;
for (cxx = 24; cxx <= 30; cxx++) { ps(cxx, walkY, 32, 'red_carpet'); ps(cxx, walkY, 42, 'orange_carpet'); }
pb(23, walkY, 32, 'flower_pot'); pb(31, walkY, 32, 'flower_pot');
pb(23, walkY, 42, 'barrel[facing=up]'); pb(24, walkY, 42, 'barrel[facing=up]');
// GALLERY ring at y=15 (walk 16), 3 deep on the east + north sides
fill(21, 15, 31, 33, 15, 33, 'dark_oak_planks');
fill(30, 15, 34, 33, 15, 41, 'dark_oak_planks');
// posts under the gallery
var gp;
for (gp = 21; gp <= 33; gp += 3) fill(gp, walkY, 33, gp, 14, 33, 'dark_oak_fence');
for (gp = 35; gp <= 41; gp += 3) fill(30, walkY, gp, 30, 14, gp, 'dark_oak_fence');
// railings (leave the stair landing clear)
for (gp = 21; gp <= 29; gp++) pb(gp, 16, 33, 'dark_oak_fence');
for (gp = 34; gp <= 40; gp++) pb(30, 16, gp, 'dark_oak_fence');
// staircase to the gallery, aimed inside the room, along the east wall
staircase(32, 41, walkY, 16, 'north', {width:2, material:'dark_oak_stairs', rail:true, support:'cut_sandstone'});
// gallery furnishings
placeBed(23, 16, 32, 'red', 'east');
pb(26, 16, 32, 'dark_oak_fence'); ps(26, 17, 32, 'white_carpet');
chairStair(27, 16, 32, 'dark_oak_stairs', 'west');
pb(22, 16, 32, 'lantern[hanging=false]');
pb(32, 16, 36, 'lectern[facing=west]');
var lz;
for (lz = 33; lz <= 41; lz += 4){ pb(21, 18, lz, 'lantern[hanging=true]'); pb(33, 18, lz, 'lantern[hanging=true]'); }
// ---------- 7. SICAKLIK INTERIOR ----------
fill(39, floorY, 29, 53, floorY, 43, marble);
fill(39, walkY, 29, 53, walkY+4, 29, 'smooth_quartz');
fill(39, walkY, 43, 53, walkY+4, 43, 'smooth_quartz');
fill(39, walkY, 29, 39, walkY+4, 43, 'smooth_quartz');
fill(53, walkY, 29, 53, walkY+4, 43, 'smooth_quartz');
// raised octagonal navel stone at (46,36)
var nx, nz, dm;
for (nx = 41; nx <= 51; nx++)
for (nz = 31; nz <= 41; nz++){
dm = Math.abs(nx-46) + Math.abs(nz-36);
if (dm <= 7 && Math.abs(nx-46) <= 5 && Math.abs(nz-36) <= 5) pb(nx, floorY+1, nz, (dm <= 4) ? 'quartz_block' : 'smooth_quartz');
}
for (nx = 44; nx <= 48; nx++)
for (nz = 34; nz <= 38; nz++)
pb(nx, floorY+2, nz, (((nx+nz) % 2) === 0) ? 'quartz_bricks' : 'calcite');
pb(46, floorY+2, 36, 'sea_lantern');
// niche basins (4) carved 1 deep into the marble walls
function nicheBasin(x, z, dx, dz){
var i;
for (i = 0; i < 3; i++) pb(x + dx, walkY + i, z + dz, 'air');
pb(x + dx, walkY + 3, z + dz, 'chiseled_sandstone');
ps(x + dx, walkY, z + dz, 'cauldron');
pb(x + dx, floorY, z + dz, 'prismarine_bricks');
pb(x + dx, walkY + 2, z + dz, 'lantern[hanging=true]');
}
nicheBasin(39, 32, -1, 0);
nicheBasin(39, 40, -1, 0);
nicheBasin(53, 32, 1, 0);
nicheBasin(53, 40, 1, 0);
// corner columns + marble benches
var cor = [[40,30],[52,30],[40,42],[52,42]];
var ci2;
for (ci2 = 0; ci2 < cor.length; ci2++){
fill(cor[ci2][0], walkY, cor[ci2][1], cor[ci2][0], 17, cor[ci2][1], 'quartz_pillar[axis=y]');
pb(cor[ci2][0], 18, cor[ci2][1], 'chiseled_quartz_block');
}
var mb2;
for (mb2 = 32; mb2 <= 40; mb2 += 2){ chairStair(40, walkY, mb2, 'quartz_stairs', 'east'); chairStair(52, walkY, mb2, 'quartz_stairs', 'west'); }
// warm-water channel + hanging lanterns
var wcx;
for (wcx = 41; wcx <= 51; wcx++){ pb(wcx, floorY, 30, 'water'); pb(wcx, floorY, 42, 'water'); }
var lp = [[42,32],[50,32],[42,40],[50,40]];
var lpi;
for (lpi = 0; lpi < lp.length; lpi++){
pb(lp[lpi][0], 18, lp[lpi][1], 'chain');
pb(lp[lpi][0], 17, lp[lpi][1], 'lantern[hanging=true]');
}
// ---------- 8. HALVET CELLS ----------
function halvet(x1, z1, x2, z2){
var cx = Math.floor((x1+x2)/2), cz = Math.floor((z1+z2)/2);
fill(x1+1, floorY, z1+1, x2-1, floorY, z2-1, 'polished_andesite');
ps(cx, walkY, cz+1, 'cauldron');
pb(cx, floorY, cz+1, 'prismarine_bricks');
chairStair(cx-1, walkY, cz-1, 'quartz_stairs', 'east');
pb(cx+1, walkY, cz-1, 'quartz_slab[type=bottom]');
pb(cx, 13, cz, 'chain');
pb(cx, 12, cz, 'lantern[hanging=true]');
}
halvet(54, 29, 60, 35);
halvet(54, 37, 60, 43);
// ---------- 9. EXTERIOR ----------
// paved forecourt + street
var fx, fz, dxx, dzz;
for (fx = 16; fx <= 40; fx++)
for (fz = 18; fz <= 28; fz++){
dxx = fx - 27; dzz = fz - 24;
if (dxx*dxx*0.45 + dzz*dzz < 70) pb(fx, padY, fz, (((fx + fz) % 5) === 0) ? 'polished_diorite' : 'smooth_sandstone');
}
for (fz = 18; fz <= 60; fz++){ pb(16, padY, fz, 'smooth_sandstone'); pb(17, padY, fz, 'sandstone'); }
// street fountain + water trough
makeCylinder(24, padY, 20, 'cut_sandstone', 3, 1, false);
makeCylinder(24, padY+1, 20, 'sandstone_wall', 3, 1, true);
makeCylinder(24, padY+1, 20, 'water', 2, 1, false);
pb(24, padY+1, 20, 'quartz_pillar[axis=y]');
pb(24, padY+2, 20, 'water');
// lamp posts
function post(x, z){
var i;
for (i = 0; i < 3; i++) pb(x, padY+1+i, z, 'cut_sandstone_wall');
pb(x, padY+4, z, 'chiseled_sandstone');
pb(x, padY+5, z, 'lantern[hanging=true]');
}
post(20, 25); post(34, 25); post(18, 46); post(62, 30);
// cypress-ish trees and shrubs
var trees = [[18,32],[18,42],[36,22],[64,36],[62,46],[30,50]];
var ti, tx, tz;
for (ti = 0; ti < trees.length; ti++){
tx = trees[ti][0]; tz = trees[ti][1];
fill(tx, padY+1, tz, tx, padY+6, tz, 'spruce_log[axis=y]');
makeSphere(tx, padY+7, tz, 'spruce_leaves[persistent=true]', 2, 3, 2, true);
makeSphere(tx, padY+5, tz, 'spruce_leaves[persistent=true]', 2, 2, 2, true);
}
var sx, sz, nv;
for (sx = 12; sx <= 72; sx++)
for (sz = 14; sz <= 60; sz++){
if (sx >= 16 && sx <= 62 && sz >= 24 && sz <= 46) continue;
nv = noise2d('perlin', sx, sz, {freq:0.3, seed:19});
if (nv > 0.85) pb(sx, padY+1, sz, 'dead_bush');
}
// entry steps up to the portico
var ex;
for (ex = 24; ex <= 30; ex++) roofStair(ex, padY+1, 26, 'sandstone_stairs', 'north');