// === BUILD PLAN ===
// Style: Art Nouveau corner apothecary, corner TURRET bay, mansard slate roof
// ORIENTATION (rule 15): the rounded corner + main door face +X / +Z (max x, max z) = the camera.
// Footprint: 21x19 rect (X18..38, Z16..34), SOUTH-EAST corner rounded r=6 around (32,28)
// Height: floor Y11 / walk Y12 (shop, 5 air) | floor2 Y17 / walk Y18 (flat, 4 air) | wall top Y21
// mansard Y22 cornice, Y23..26 slate flanks, Y27 deck; corner TURRET cone Y23..30
//
// GROUND (top-down, +X right, +Z down):
// #####################
// # bottles shelf wall #
// # #
// # tables counter#
// # ST # ST = staircase (climbs west, walk12 -> walk18)
// # WWW
// ##WW (bay)WW
// #####WWW###WW#DD### D = door on the rounded bay, facing +Z
//
// PROCESS: LAYERED (build-rules 14): 1) form in blue_wool/red_wool placeholders
// 2) carve openings with clearMasked(onlyMaterial) 3) TEXTURE LAST via replaceMasked
// MATERIALS PLAN:
// plinth : deepslate ramp - WHY: dark base = fake AO, grounds the facade
// ground : gradient dark_prismarine->green_terracotta->green_concrete - WHY: glazed-tile green, dark low
// upper : gradient brown-> white_terracotta -> smooth_quartz - WHY: pale stucco CONTRAST over green
// ironwork : iron_bars fanlights, balcony rail, canopy hangers - WHY: the whiplash signature
// roof : deepslate tile/brick stair noise + turret cone - WHY: slate shingle variation
// Rooms: shop (counter L, bottle wall, brewing bench, seating) / flat (bed, kitchen nook, sofa, balcony)
// STAIR PLAN: D = 18-12 = 6 -> staircase(34,22,12,18,"west") 7 cells, lands flush at (28,18,22)
// === END PLAN ===
var X0 = 18, X1 = 38, Z0 = 16, Z1 = 34;
var R = 6, CX = X1 - R, CZ = Z1 - R;
var padY = 10, floorY = 11, walkY = 12, floor2Y = 17, walkY2 = 18, wallTopY = 21, roofY = 22;
var PH_WALL = 'blue_wool';
function inside(x, z) {
if (x < X0 || x > X1 || z < Z0 || z > Z1) return false;
if (x > CX && z > CZ) {
var dx = x - CX, dz = z - CZ;
return (dx * dx + dz * dz) <= (R * R + 0.6);
}
return true;
}
function insideK(x, z, k) {
var i, j;
for (i = -k; i <= k; i++) for (j = -k; j <= k; j++) if (!inside(x + i, z + j)) return false;
return true;
}
function ringK(x, z, k) {
if (!insideK(x, z, k)) return false;
return !insideK(x + 1, z, k) || !insideK(x - 1, z, k) || !insideK(x, z + 1, k) || !insideK(x, z - 1, k);
}
function shell(x, z) { return ringK(x, z, 0); }
function isArc(x, z) { return x > CX && z > CZ; }
var x, y, z, i, k;
// === 1. TERRAIN (superpowers, flat pad under the build) ===
var land = blob(30, 28, 32, {irregularity:0.4, seed:23});
var hbase = hills({base:8, amp:3, scale:0.04, seed:11});
var pad = flatten(hbase, {x0:X0-7, z0:Z0-7, x1:X1+8, z1:Z1+8}, padY, 8);
var cobblePat = noisePalette([{block:'cobblestone',weight:38},{block:'andesite',weight:26},{block:'stone',weight:26},{block:'gravel',weight:10}], {seed:17, freq:0.22});
var soilPat = patches([{block:'grass_block',w:66},{block:'coarse_dirt',w:22},{block:'moss_block',w:12}], 0.055, 7);
var groundMat = function (gx, gz) {
if (gx >= X1 + 3 || gz >= Z1 + 3) return cobblePat(gx, 0, gz); // the two streets, on the camera side
if (gx >= X1 + 1 || gz >= Z1 + 1) return 'smooth_stone'; // kerb / pavement
return soilPat(gx, gz);
};
surface(land, pad, groundMat, {sub:'dirt', deep:'stone', depth:4});
// === 2. FORM IN PLACEHOLDERS (layered step 1) ===
fill(X0 - 1, floorY, Z0 - 1, X1 + 1, roofY + 10, Z1 + 1, b('air'));
for (x = X0; x <= X1; x++) for (z = Z0; z <= Z1; z++) {
if (!inside(x, z)) continue;
pb(x, floorY, z, 'stone_bricks'); // structural slab under the shop floor
if (shell(x, z)) for (y = floorY + 1; y <= wallTopY; y++) pb(x, y, z, PH_WALL);
}
// === 3. CARVE OPENINGS BY MASK (layered step 2) ===
// straight facades: 1-block-thick wall slots, mask keeps the cut inside the wall only
function slotStraight(x1, z1, x2, z2, y1, y2) { clearMasked(x1, y1, z1, x2, y2, z2, onlyMaterial(PH_WALL)); }
// south facade (z=Z1) shop windows + upper windows
slotStraight(21, Z1, 23, Z1, 13, 16); slotStraight(25, Z1, 27, Z1, 13, 16);
slotStraight(21, Z1, 23, Z1, 19, 21); slotStraight(25, Z1, 27, Z1, 19, 21);
// east facade (x=X1) shop + upper
slotStraight(X1, 19, X1, 21, 13, 16); slotStraight(X1, 23, X1, 25, 13, 16);
slotStraight(X1, 19, X1, 21, 19, 21); slotStraight(X1, 23, X1, 25, 19, 21);
// west + north: upper only (service sides)
slotStraight(X0, 21, X0, 23, 19, 21); slotStraight(X0, 26, X0, 28, 19, 21);
slotStraight(23, Z0, 25, Z0, 19, 21); slotStraight(30, Z0, 32, Z0, 19, 21);
// the rounded bay: shopfront glass all the way round, door at the +Z/+X diagonal
var doorX = 35, doorZ = 33, best = 999;
for (x = CX + 1; x <= X1; x++) for (z = CZ + 1; z <= Z1; z++) {
if (!shell(x, z)) continue;
var dd = Math.abs(x - (CX + R * 0.62)) + Math.abs(z - (CZ + R * 0.78));
if (dd < best) { best = dd; doorX = x; doorZ = z; }
}
for (x = CX + 1; x <= X1; x++) for (z = CZ + 1; z <= Z1; z++) {
if (!shell(x, z)) continue;
var isDoor = (Math.abs(x - doorX) + Math.abs(z - doorZ) <= 1);
for (y = 13; y <= 16; y++) pb(x, y, z, 'air');
for (y = 19; y <= 21; y++) pb(x, y, z, 'air');
if (isDoor) { pb(x, walkY, z, 'air'); pb(x, walkY + 1, z, 'air'); }
}
// === 4. TEXTURE LAST (layered step 3) ===
var plinthPal = noisePalette([{block:'polished_deepslate',weight:44},{block:'deepslate_tiles',weight:34},{block:'deepslate_bricks',weight:22}], {seed:5, freq:0.17});
var greenPal = gradientPalette(13, 16, [{block:'dark_prismarine',from:0},{block:'green_terracotta',from:0.4},{block:'green_concrete',from:0.78}], {noise:0.22, seed:9});
var creamPal = gradientPalette(18, 21, [{block:'brown_terracotta',from:0},{block:'white_terracotta',from:0.3},{block:'smooth_quartz',from:0.78}], {noise:0.2, seed:12});
replaceMasked(X0 - 1, floorY, Z0 - 1, X1 + 1, walkY, Z1 + 1, plinthPal, onlyMaterial(PH_WALL));
replaceMasked(X0 - 1, walkY + 1, Z0 - 1, X1 + 1, 16, Z1 + 1, greenPal, onlyMaterial(PH_WALL));
replaceMasked(X0 - 1, floor2Y, Z0 - 1, X1 + 1, floor2Y, Z1 + 1, b('dark_prismarine'), onlyMaterial(PH_WALL)); // string course
replaceMasked(X0 - 1, walkY2, Z0 - 1, X1 + 1, wallTopY, Z1 + 1, creamPal, onlyMaterial(PH_WALL));
// glaze the openings (mask: only into the air we just carved, never over the build)
function glazeStraight(x1, z1, x2, z2, y1, y2, blk) { fillMasked(x1, y1, z1, x2, y2, z2, b(blk), onlyAir()); }
glazeStraight(21, Z1, 23, Z1, 13, 15, 'glass'); glazeStraight(25, Z1, 27, Z1, 13, 15, 'glass');
glazeStraight(21, Z1, 23, Z1, 16, 16, 'iron_bars'); glazeStraight(25, Z1, 27, Z1, 16, 16, 'iron_bars');
glazeStraight(X1, 19, X1, 21, 13, 15, 'glass'); glazeStraight(X1, 23, X1, 25, 13, 15, 'glass');
glazeStraight(X1, 19, X1, 21, 16, 16, 'iron_bars'); glazeStraight(X1, 23, X1, 25, 16, 16, 'iron_bars');
glazeStraight(21, Z1, 23, Z1, 19, 20, 'glass_pane'); glazeStraight(25, Z1, 27, Z1, 19, 20, 'glass_pane');
glazeStraight(X1, 19, X1, 21, 19, 20, 'glass_pane'); glazeStraight(X1, 23, X1, 25, 19, 20, 'glass_pane');
glazeStraight(X0, 21, X0, 23, 19, 20, 'glass_pane'); glazeStraight(X0, 26, X0, 28, 19, 20, 'glass_pane');
glazeStraight(23, Z0, 25, Z0, 19, 20, 'glass_pane'); glazeStraight(30, Z0, 32, Z0, 19, 20, 'glass_pane');
glazeStraight(21, Z1, 23, Z1, 21, 21, 'iron_bars'); glazeStraight(25, Z1, 27, Z1, 21, 21, 'iron_bars');
glazeStraight(X1, 19, X1, 21, 21, 21, 'iron_bars'); glazeStraight(X1, 23, X1, 25, 21, 21, 'iron_bars');
glazeStraight(X0, 21, X0, 23, 21, 21, 'iron_bars'); glazeStraight(X0, 26, X0, 28, 21, 21, 'iron_bars');
glazeStraight(23, Z0, 25, Z0, 21, 21, 'iron_bars'); glazeStraight(30, Z0, 32, Z0, 21, 21, 'iron_bars');
// bay glass (curved wall: cell by cell so nothing bleeds off the arc)
for (x = CX + 1; x <= X1; x++) for (z = CZ + 1; z <= Z1; z++) {
if (!shell(x, z)) continue;
var dr = (Math.abs(x - doorX) + Math.abs(z - doorZ) <= 1);
if (!dr) { for (y = 13; y <= 15; y++) pb(x, y, z, 'glass'); pb(x, 16, z, 'iron_bars'); }
for (y = 19; y <= 20; y++) if (!(dr && y === 19)) pb(x, y, z, 'glass_pane');
pb(x, 21, z, 'iron_bars');
}
ps(doorX, walkY, doorZ, 'dark_oak_door[facing=south,half=lower,hinge=left]');
ps(doorX, walkY + 1, doorZ, 'dark_oak_door[facing=south,half=upper,hinge=right]');
pb(doorX, 14, doorZ, 'glass'); pb(doorX, 15, doorZ, 'glass'); pb(doorX, 16, doorZ, 'iron_bars');
// === 5. FACADE RELIEF — protruding pilasters, sills, quoins ===
function pilaster(px, pz, dx, dz) {
var yy;
for (yy = floorY; yy <= wallTopY; yy++) pb(px + dx, yy, pz + dz, (yy <= walkY || yy >= floor2Y) ? 'polished_deepslate' : 'deepslate_tiles');
ps(px + dx, floor2Y, pz + dz, 'deepslate_tile_slab[type=top]');
ps(px + dx, wallTopY + 1, pz + dz, 'deepslate_tile_slab[type=bottom]');
}
pilaster(20, Z1, 0, 1); pilaster(24, Z1, 0, 1); pilaster(28, Z1, 0, 1);
pilaster(X1, 18, 1, 0); pilaster(X1, 22, 1, 0); pilaster(X1, 26, 1, 0);
pilaster(X0, 20, -1, 0); pilaster(X0, 25, -1, 0);
for (y = floorY; y <= wallTopY; y++) {
pb(X0 - 1, y, Z0, 'polished_deepslate'); pb(X0, y, Z0 - 1, 'polished_deepslate');
pb(X1 + 1, y, Z0, 'polished_deepslate'); pb(X1, y, Z0 - 1, 'polished_deepslate');
pb(X0 - 1, y, Z1, 'polished_deepslate'); pb(X0, y, Z1 + 1, 'polished_deepslate');
}
// window sills / lintels on the upper floor
for (x = 21; x <= 27; x++) { ps(x, walkY2 - 0, Z1 + 1, 'smooth_quartz_slab[type=top]'); }
for (z = 19; z <= 25; z++) { ps(X1 + 1, walkY2 - 0, z, 'smooth_quartz_slab[type=top]'); }
// === 6. CURVED GLASS CANOPY + IRON BALCONY (camera side only) ===
for (x = X0 - 1; x <= X1 + 2; x++) for (z = Z0 - 1; z <= Z1 + 2; z++) {
if (inside(x, z)) continue;
var touch = inside(x + 1, z) || inside(x - 1, z) || inside(x, z + 1) || inside(x, z - 1);
if (!touch) continue;
if (x < X0 || z < Z0) continue;
pb(x, floor2Y, z, 'glass');
ps(x, floor2Y - 1, z, 'chain[axis=y]');
if (isArc(x, z) || (x >= 20 && x <= 28 && z > Z1) || (z >= 18 && z <= 26 && x > X1)) {
ps(x, walkY2, z, 'smooth_quartz_slab[type=bottom]');
pb(x, walkY2 + 1, z, 'iron_bars');
}
}
ps(doorX, walkY2, doorZ, 'dark_oak_door[facing=south,half=lower,hinge=left]');
ps(doorX, walkY2 + 1, doorZ, 'dark_oak_door[facing=south,half=upper,hinge=right]');
pb(doorX, walkY2 + 1, doorZ + 1, 'air');
// === 7. FLOORS + BEAMS ===
var boardPal = noisePalette([{block:'dark_oak_planks',weight:58},{block:'spruce_planks',weight:42}], {seed:19, freq:0.2});
for (x = X0 + 1; x <= X1 - 1; x++) for (z = Z0 + 1; z <= Z1 - 1; z++) {
if (!insideK(x, z, 1)) continue;
pb(x, floor2Y, z, boardPal(x, floor2Y, z));
pb(x, roofY, z, 'dark_oak_planks'); // attic floor: closes the flat
}
for (x = X0 + 1; x <= X1 - 1; x++) { if (insideK(x, 22, 1)) ps(x, floor2Y - 1, 22, 'stripped_dark_oak_log[axis=x]'); if (insideK(x, 28, 1)) ps(x, floor2Y - 1, 28, 'stripped_dark_oak_log[axis=x]'); }
// shop floor: black/white Art Nouveau tiling
for (x = X0 + 1; x <= X1 - 1; x++) for (z = Z0 + 1; z <= Z1 - 1; z++) {
if (!insideK(x, z, 1)) continue;
pb(x, floorY, z, (((x >> 1) + (z >> 1)) % 2 === 0) ? 'polished_diorite' : 'polished_blackstone');
}
// === 8. MANSARD ROOF + CORNER TURRET ===
var slatePal = noisePalette([{block:'deepslate_tiles',weight:48},{block:'polished_deepslate',weight:30},{block:'deepslate_bricks',weight:22}], {seed:27, freq:0.18});
var slateStairPal = noisePalette([{block:'deepslate_tile_stairs',weight:62},{block:'deepslate_brick_stairs',weight:38}], {seed:29, freq:0.2});
for (x = X0 - 1; x <= X1 + 1; x++) for (z = Z0 - 1; z <= Z1 + 1; z++) {
if (inside(x, z)) continue;
var tc = inside(x + 1, z) || inside(x - 1, z) || inside(x, z + 1) || inside(x, z - 1);
if (tc) { pb(x, roofY, z, 'polished_deepslate'); ps(x, roofY + 1, z, 'deepslate_tile_slab[type=bottom]'); }
}
for (x = X0; x <= X1; x++) for (z = Z0; z <= Z1; z++) if (shell(x, z)) pb(x, roofY, z, 'polished_deepslate');
for (k = 0; k <= 3; k++) {
var ry = roofY + 1 + k;
for (x = X0; x <= X1; x++) for (z = Z0; z <= Z1; z++) {
if (!ringK(x, z, k)) continue;
var oN = !insideK(x, z - 1, k), oS = !insideK(x, z + 1, k), oW = !insideK(x - 1, z, k), oE = !insideK(x + 1, z, k);
var cnt = (oN?1:0)+(oS?1:0)+(oW?1:0)+(oE?1:0);
if (cnt > 1) { pb(x, ry, z, slatePal(x, ry, z)); continue; }
roofStair(x, ry, z, slateStairPal(x, ry, z), oN ? 'north' : (oS ? 'south' : (oW ? 'west' : 'east')));
}
}
for (x = X0; x <= X1; x++) for (z = Z0; z <= Z1; z++) if (insideK(x, z, 4)) pb(x, roofY + 5, z, slatePal(x, roofY + 5, z));
for (x = X0; x <= X1; x++) for (z = Z0; z <= Z1; z++) if (insideK(x, z, 6)) ps(x, roofY + 6, z, 'deepslate_tile_slab[type=bottom]');
// corner TURRET over the rounded bay (radius >= 4 so every flat side keeps 3+ blocks — rule 6)
makeCylinder(CX, roofY, CZ, slatePal, R - 0.4, 3, true);
makeCone(CX, roofY + 3, CZ, slateStairPal, R - 0.4, 7, false);
pb(CX, roofY + 10, CZ, 'polished_deepslate');
pb(CX, roofY + 11, CZ, 'lightning_rod');
// dormer on the south flank
function dormer(dx, dz) {
var o, yy;
for (o = -1; o <= 1; o++) {
for (yy = roofY + 1; yy <= roofY + 3; yy++) pb(dx + o, yy, dz, (o === 0 && yy > roofY + 1) ? 'glass_pane' : 'polished_deepslate');
roofStair(dx + o, roofY + 4, dz, 'deepslate_tile_stairs', 'south');
for (yy = roofY + 1; yy <= roofY + 4; yy++) pb(dx + o, yy, dz - 1, 'deepslate_tiles');
}
}
dormer(22, Z1); dormer(27, Z1);
// chimney
fill(X0 + 2, floor2Y, Z0 + 1, X0 + 2, roofY + 8, Z0 + 1, noisePalette([{block:'bricks',weight:72},{block:'mud_bricks',weight:28}], {seed:33}));
ps(X0 + 2, roofY + 9, Z0 + 1, 'brick_slab[type=bottom]');
// === 9. STAIR (walk 12 -> walk 18), reserved corridor, nothing decorated inside it ===
var topCell = staircase(34, 22, walkY, walkY2, 'west', {width:1, material:'dark_oak_stairs', rail:true, support:'polished_deepslate'});
// === 10. SHOP INTERIOR ===
for (z = 18; z <= 30; z++) for (y = walkY; y <= walkY + 3; y++) pb(X0 + 1, y, z, ((z + y) % 3 === 0) ? 'chiseled_bookshelf' : 'bookshelf'); // bottle wall
for (z = 19; z <= 29; z += 2) ps(X0 + 1, walkY + 4, z, 'dark_oak_slab[type=top]');
for (z = 25; z <= 31; z++) { pb(34, walkY, z, 'stripped_dark_oak_log[axis=z]'); ps(34, walkY + 1, z, 'dark_oak_stairs[facing=west,half=top]'); }
for (x = 29; x <= 33; x++) { pb(x, walkY, 31, 'stripped_dark_oak_log[axis=x]'); ps(x, walkY + 1, 31, 'dark_oak_stairs[facing=north,half=top]'); }
ps(35, walkY, 26, 'brewing_stand'); ps(35, walkY, 28, 'brewing_stand'); ps(36, walkY, 30, 'cauldron[level=0]');
pb(35, walkY, 30, 'barrel'); pb(36, walkY, 26, 'crafting_table'); ps(36, walkY, 28, 'composter');
ps(32, walkY + 2, 31, 'flower_pot'); ps(30, walkY + 2, 31, 'candle[candles=2]');
for (x = 22; x <= 30; x++) for (z = 20; z <= 27; z++) if (insideK(x, z, 1)) pb(x, walkY, z, 'green_carpet');
pb(24, walkY, 23, 'dark_oak_fence'); ps(24, walkY + 1, 23, 'oak_pressure_plate');
chairStair(23, walkY, 23, 'dark_oak_stairs', 'east'); chairStair(25, walkY, 23, 'dark_oak_stairs', 'west');
pb(28, walkY, 26, 'dark_oak_fence'); ps(28, walkY + 1, 26, 'oak_pressure_plate');
chairStair(27, walkY, 26, 'dark_oak_stairs', 'east'); chairStair(29, walkY, 26, 'dark_oak_stairs', 'west');
var lampsG = [[22, 20], [30, 20], [24, 29], [32, 27]];
for (i = 0; i < lampsG.length; i++) { ps(lampsG[i][0], floor2Y - 1, lampsG[i][1], 'chain[axis=y]'); ps(lampsG[i][0], floor2Y - 2, lampsG[i][1], 'lantern[hanging=true]'); }
// === 11. FLAT INTERIOR (upper) ===
placeBed(21, walkY2, 20, 'light_blue', 'north');
pb(22, walkY2, 19, 'dark_oak_fence'); ps(22, walkY2 + 1, 19, 'oak_pressure_plate'); pb(22, walkY2 + 2, 19, 'lantern');
for (x = 26; x <= 31; x++) for (z = 24; z <= 29; z++) if (insideK(x, z, 1)) pb(x, walkY2, z, 'light_gray_carpet');
pb(28, walkY2, 26, 'dark_oak_fence'); ps(28, walkY2 + 1, 26, 'oak_pressure_plate');
chairStair(27, walkY2, 26, 'spruce_stairs', 'east'); chairStair(29, walkY2, 26, 'spruce_stairs', 'west');
for (i = 0; i < 3; i++) chairStair(31 + i, walkY2, 29, 'spruce_stairs', 'north');
// kitchen nook by the chimney
pb(X0 + 2, walkY2, Z0 + 2, 'stripped_spruce_log[axis=y]'); ps(X0 + 2, walkY2 + 1, Z0 + 2, 'spruce_stairs[facing=south,half=top]');
ps(X0 + 3, walkY2, Z0 + 1, 'furnace[facing=south,lit=false]'); ps(X0 + 3, walkY2 + 1, Z0 + 1, 'iron_trapdoor[facing=south,half=bottom,open=false]');
ps(X0 + 4, walkY2, Z0 + 1, 'water_cauldron[level=3]');
pb(X0 + 2, walkY2, Z0 + 1, 'campfire[lit=true]');
for (x = 30; x <= 33; x++) for (y = walkY2; y <= walkY2 + 1; y++) pb(x, y, Z0 + 1, 'bookshelf');
var lampsU = [[24, 21], [30, 25], [26, 29]];
for (i = 0; i < lampsU.length; i++) { ps(lampsU[i][0], roofY - 1, lampsU[i][1], 'chain[axis=y]'); ps(lampsU[i][0], roofY - 2, lampsU[i][1], 'lantern[hanging=true]'); }
// === 12. STREET & LANDSCAPING (camera side) ===
function streetLamp(lx, lz) {
var yy;
pb(lx, padY, lz, 'polished_deepslate');
for (yy = padY + 1; yy <= padY + 4; yy++) pb(lx, yy, lz, 'dark_oak_fence');
pb(lx, padY + 5, lz, 'polished_deepslate');
ps(lx - 1, padY + 5, lz, 'chain[axis=y]'); ps(lx - 1, padY + 4, lz, 'lantern[hanging=true]');
ps(lx + 1, padY + 5, lz, 'chain[axis=y]'); ps(lx + 1, padY + 4, lz, 'lantern[hanging=true]');
}
streetLamp(41, 30); streetLamp(26, 39);
function planter(px, pz) {
var a, c;
for (a = 0; a < 2; a++) for (c = 0; c < 2; c++) {
pb(px + a, padY, pz + c, 'polished_deepslate');
pb(px + a, padY + 1, pz + c, ((a + c) % 2 === 0) ? 'flowering_azalea_leaves' : 'moss_block');
}
}
planter(41, 19); planter(41, 24); planter(19, 37); planter(24, 37);
placeTree(44, padY + 1, 35, 'oak');
placeTree(16, padY + 1, 38, 'birch');
ps(X1 + 1, 15, 22, 'dark_oak_wall_sign[facing=east]');
ps(24, 15, Z1 + 1, 'dark_oak_wall_sign[facing=south]');
for (x = X1 + 2; x <= X1 + 4; x++) for (z = Z1 + 2; z <= Z1 + 4; z++) ps(x, padY, z, 'smooth_stone_slab[type=top]');
// === FIX PASS: make the CORNER TURRET read as its own volume (copper vs slate) ===
var copperPal = noisePalette([{block:'exposed_copper',weight:42},{block:'weathered_copper',weight:34},{block:'cut_copper',weight:24}], {seed:47, freq:0.2});
var copperLight = noisePalette([{block:'cut_copper',weight:55},{block:'exposed_copper',weight:45}], {seed:48, freq:0.22});
// copper drum with a cornice ring, then a copper cone cap
makeCylinder(CX, roofY, CZ, copperLight, R - 0.4, 3, true);
makeCylinder(CX, roofY + 2, CZ, b('cut_copper_slab[type=top]'), R + 0.4, 1, true);
makeCone(CX, roofY + 3, CZ, copperPal, R - 0.4, 8, false);
pb(CX, roofY + 11, CZ, 'cut_copper');
pb(CX, roofY + 12, CZ, 'lightning_rod');
// iron cresting round the base of the cone so the turret has an outline
var fa;
for (fa = 0; fa < 360; fa += 20) {
var rx = CX + Math.round((R - 1) * Math.cos(fa * Math.PI / 180));
var rz2 = CZ + Math.round((R - 1) * Math.sin(fa * Math.PI / 180));
if (rx > X1 || rz2 > Z1) continue;
pb(rx, roofY + 3, rz2, 'iron_bars');
}
// copper cornice band on the main mansard eave = the two roofs stop being one dark mass
var cx3, cz3;
for (cx3 = X0 - 1; cx3 <= X1 + 1; cx3++) for (cz3 = Z0 - 1; cz3 <= Z1 + 1; cz3++) {
if (inside(cx3, cz3)) continue;
var tt2 = inside(cx3 + 1, cz3) || inside(cx3 - 1, cz3) || inside(cx3, cz3 + 1) || inside(cx3, cz3 - 1);
if (tt2) { pb(cx3, roofY, cz3, copperLight(cx3, roofY, cz3)); ps(cx3, roofY + 1, cz3, 'cut_copper_slab[type=bottom]'); }
}