// === BUILD PLAN ===
// Style: Ethiopian rock-hewn monolith. Knowledge routed by search_docs(related) ->
// Egyptian (BATTERED walls, HYPOSTYLE hall, CAVETTO cornice, carved bands)
// + Cliffs & Rock Faces (horizontal STRATA bands, stairs/buttons as rock protrusions).
// Footprint: LATIN CROSS - long nave x38..57 z30..68, transept x28..67 z40..53.
// Free-standing inside a 61x53 trench cut 15 blocks into a red mesa.
// Height: court floor Y2 | body Y3..16 in THREE BATTERED TIERS (each inset 1) | roof Y17 + motif Y18
// mesa top Y17, so the roof sits flush with the plateau (as at Bete Giyorgis).
//
// SECTION (looking west):
// Y18 .......[+]cross motif[+].......
// Y17 =======[ roof slab + cavetto ]======= <- mesa level
// Y14 | tier 3 (inset 2) |
// Y9 | tier 2 (inset 1) |
// Y3 | tier 1 (base) |
// Y2 ~~~~~ courtyard floor ~~~~~
//
// HYPOSTYLE NAVE (top-down, 1 char = 2 blocks):
// #############
// # O O O # O = 2x2 monolithic column (Egyptian hypostyle: 2x2, spacing 3-4)
// # O O O # A = altar bay (north end)
// ## crossing ##
// # O O O #
// ######D###### D = door -> porch -> flight down to the courtyard
//
// MATERIALS PLAN (DIRECT - palettes passed straight into fill, no placeholders):
// bedrock/trench : strata() position-palette, horizontal 3-block bands - WHY: Cliffs doc, reads as CUT rock
// body : red_sandstone(40)+cut(25)+smooth(20)+terracotta(15) noise - WHY: one monolithic stone
// carved bands : chiseled_red_sandstone every tier top - WHY: Egyptian hieroglyph band rule
// cornice : cavetto flare, red_sandstone_stairs upside-down - WHY: Egyptian cavetto = wall_depth
// interior : smooth_red_sandstone floor, sandstone_wall columns, red/orange carpet, candles
// STAIR PLAN: L-shaped rock-cut descent, WEST side. flight A walk3->walk10 heading west (7),
// landing 7x9 at walk10, flight B walk10->walk18 heading north (8). Porch: walk3->walk6.
// === END PLAN ===
var courtY = 2, courtWalk = 3;
var floorY = 5, walkY = 6, ceilY = 16;
var t1 = 3, t2 = 9, t3 = 14; // tier bases
var roofY = 17, motifY = 18, mesaY = 17;
// ---- LATIN CROSS ----
var NX1 = 38, NX2 = 57, NZ1 = 30, NZ2 = 68; // nave
var TX1 = 28, TX2 = 67, TZ1 = 40, TZ2 = 53; // transept
function cross(x, z, g) {
if (x >= NX1 - g && x <= NX2 + g && z >= NZ1 - g && z <= NZ2 + g) return true;
if (x >= TX1 - g && x <= TX2 + g && z >= TZ1 - g && z <= TZ2 + g) return true;
return false;
}
// interior (walls 4 thick, battered)
var INX1 = 42, INX2 = 53, INZ1 = 34, INZ2 = 64;
var ITX1 = 32, ITX2 = 63, ITZ1 = 44, ITZ2 = 49;
function inHall(x, z) {
if (x >= INX1 && x <= INX2 && z >= INZ1 && z <= INZ2) return true;
if (x >= ITX1 && x <= ITX2 && z >= ITZ1 && z <= ITZ2) return true;
return false;
}
// ===== 1. MESA OF RED BEDROCK — strata bands (Cliffs & Rock Faces) =====
var STRATA = ['granite', 'terracotta', 'red_sandstone', 'brown_terracotta', 'stone', 'red_sandstone'];
function strata(x, y, z) {
var wob = noise2d('perlin', x, z, { freq: 0.09, seed: 15 });
var band = Math.floor((y + wob * 2.5 + 6) / 3) % STRATA.length;
if (band < 0) band = 0;
return STRATA[band];
}
var land = blob(48, 48, 45, { irregularity: 0.26, seed: 5 });
var lx, lz;
for (lx = 0; lx < 96; lx++) {
for (lz = 0; lz < 96; lz++) {
if (land(lx, lz)) fill(lx, 0, lz, lx, mesaY - 1, lz, strata);
}
}
var h = hills({ base: mesaY, amp: 5, scale: 0.032, seed: 11, octaves: 2 });
var pad = flatten(h, { x0: 10, z0: 14, x1: 86, z1: 82 }, mesaY, 9);
surface(land, pad, patches([
{ block: 'coarse_dirt', w: 34 },
{ block: 'terracotta', w: 24 },
{ block: 'red_sand', w: 18 },
{ block: 'grass_block', w: 14 },
{ block: 'granite', w: 10 }
], 0.045, 17), { sub: 'coarse_dirt', deep: 'granite', depth: 3 });
// ===== 2. TRENCH + L-SHAPED ROCK-CUT DESCENT =====
var CX1 = 18, CX2 = 78, CZ1 = 22, CZ2 = 74;
fill(CX1, courtY + 1, CZ1, CX2, 28, CZ2, 'air');
fill(CX1, courtY, CZ1, CX2, courtY, CZ2, noisePalette([
{ block: 'smooth_red_sandstone', weight: 35 },
{ block: 'red_sandstone', weight: 25 },
{ block: 'polished_andesite', weight: 20 },
{ block: 'stone', weight: 12 },
{ block: 'gravel', weight: 8 }
], { seed: 44, freq: 0.1 }));
// flight A corridor: walk = 3 + (15 - x), clamped, over x 2..18 / z 44..52
var ax, aw;
for (ax = 2; ax <= 18; ax++) {
aw = ax >= 15 ? courtWalk : courtWalk + (15 - ax);
if (aw > 10) aw = 10;
fill(ax, aw, 44, ax, 28, 52, 'air');
}
// flight B corridor: walk = 10 + (44 - z), over z 36..43 / x 2..9
var bz, bw;
for (bz = 36; bz <= 43; bz++) {
bw = 10 + (44 - bz);
if (bw > mesaY + 1) bw = mesaY + 1;
fill(2, bw, bz, 9, 28, bz, 'air');
}
fill(2, mesaY + 1, 28, 9, 28, 36, 'air'); // canyon mouth on the mesa
staircase(15, 48, courtWalk, 10, 'west', { width: 3, material: 'polished_andesite_stairs', support: 'polished_andesite' });
landing(3, 10, 45, 6, 7, 'smooth_red_sandstone');
staircase(5, 44, 10, mesaY + 1, 'north', { width: 3, material: 'polished_andesite_stairs', support: 'polished_andesite' });
// rock protrusions on the cut faces (Cliffs doc: stairs/buttons as detail)
var pz, pxx;
for (pz = 26; pz <= 70; pz += 5) {
ps(CX1, courtWalk + 3, pz, 'stone_button[face=wall,facing=east]');
ps(CX2, courtWalk + 5, pz + 2, 'stone_button[face=wall,facing=west]');
pb(CX1, courtWalk + 7, pz + 1, 'glow_lichen');
}
for (pxx = 24; pxx <= 72; pxx += 6) {
ps(pxx, courtWalk + 4, CZ1, 'stone_button[face=wall,facing=south]');
ps(pxx + 2, courtWalk + 6, CZ2, 'stone_button[face=wall,facing=north]');
}
// ===== 3. THE MONOLITH — THREE BATTERED TIERS, DIRECT PALETTES =====
var bodyPal = noisePalette([
{ block: 'red_sandstone', weight: 30 },
{ block: 'cut_red_sandstone', weight: 20 },
{ block: 'smooth_red_sandstone', weight: 16 },
{ block: 'terracotta', weight: 14 },
{ block: 'brown_terracotta', weight: 12 },
{ block: 'granite', weight: 8 }
], { seed: 7, freq: 0.1 });
var darkBase = noisePalette([
{ block: 'polished_basalt', weight: 34 },
{ block: 'brown_terracotta', weight: 26 },
{ block: 'basalt', weight: 22 },
{ block: 'deepslate_bricks', weight: 18 }
], { seed: 71, freq: 0.11 });
var tx, tz;
for (tx = NX1 - 2; tx <= NX2 + 2; tx++) {
for (tz = NZ1 - 2; tz <= NZ2 + 2; tz++) {
if (cross(tx, tz, 1)) fill(tx, t1, tz, tx, t1 + 1, tz, darkBase); // stylobate, 1 proud (dark)
if (cross(tx, tz, 0)) fill(tx, t1 + 2, tz, tx, t2 - 1, tz, bodyPal);
if (cross(tx, tz, -1)) fill(tx, t2, tz, tx, t3 - 1, tz, bodyPal);
if (cross(tx, tz, -2)) fill(tx, t3, tz, tx, ceilY, tz, bodyPal);
if (cross(tx, tz, -1)) fill(tx, roofY, tz, tx, roofY, tz, noisePalette([
{ block: 'smooth_red_sandstone', weight: 50 },
{ block: 'cut_red_sandstone', weight: 30 },
{ block: 'red_sandstone', weight: 20 }
], { seed: 8, freq: 0.13 }));
}
}
// carved bands + CAVETTO cornice at every tier top (Egyptian)
function bandAndCornice(g, yBand) {
var bx, bz2, d;
var dx = [1, -1, 0, 0], dz = [0, 0, 1, -1], nm = ['east', 'west', 'south', 'north'];
for (bx = NX1 - 3; bx <= NX2 + 3; bx++) {
for (bz2 = NZ1 - 3; bz2 <= NZ2 + 3; bz2++) {
if (!cross(bx, bz2, g)) continue;
for (d = 0; d < 4; d++) {
if (cross(bx + dx[d], bz2 + dz[d], g)) continue;
pb(bx, yBand, bz2, 'polished_basalt');
roofStair(bx + dx[d], yBand, bz2 + dz[d], 'red_sandstone_stairs', nm[d], 'top');
}
}
}
}
bandAndCornice(0, t2 - 1);
bandAndCornice(-1, t3 - 1);
bandAndCornice(-2, ceilY);
// pilaster relief: proud strips every 4 blocks up each face
var qx, qz, d2;
var ddx = [1, -1, 0, 0], ddz = [0, 0, 1, -1];
for (qx = NX1 - 2; qx <= NX2 + 2; qx++) {
for (qz = NZ1 - 2; qz <= NZ2 + 2; qz++) {
if (!cross(qx, qz, 0)) continue;
if ((qx + qz) % 4 !== 0) continue;
for (d2 = 0; d2 < 4; d2++) {
if (cross(qx + ddx[d2], qz + ddz[d2], 0)) continue;
fill(qx + ddx[d2], t1 + 2, qz + ddz[d2], qx + ddx[d2], t2 - 2, qz + ddz[d2], noisePalette([{ block: 'brown_terracotta', weight: 45 }, { block: 'granite', weight: 30 }, { block: 'cut_red_sandstone', weight: 25 }], { seed: 77, freq: 0.14 }));
}
}
}
// ===== 4. HOLLOW THE HYPOSTYLE HALL =====
fill(INX1, walkY, INZ1, INX2, ceilY - 1, INZ2, 'air');
fill(ITX1, walkY, ITZ1, ITX2, ceilY - 1, ITZ2, 'air');
fill(INX1, floorY, INZ1, INX2, floorY, INZ2, noisePalette([
{ block: 'smooth_red_sandstone', weight: 45 },
{ block: 'cut_red_sandstone', weight: 30 },
{ block: 'polished_andesite', weight: 25 }
], { seed: 61, freq: 0.12 }));
fill(ITX1, floorY, ITZ1, ITX2, floorY, ITZ2, noisePalette([
{ block: 'smooth_red_sandstone', weight: 45 },
{ block: 'cut_red_sandstone', weight: 30 },
{ block: 'polished_andesite', weight: 25 }
], { seed: 61, freq: 0.12 }));
// hypostyle: 2x2 columns, spacing 4
var colX = [44, 50], colZ = [36, 41, 53, 58, 62];
var ci, cj;
for (ci = 0; ci < colX.length; ci++) {
for (cj = 0; cj < colZ.length; cj++) {
fill(colX[ci], walkY, colZ[cj], colX[ci] + 1, ceilY - 2, colZ[cj] + 1, 'cut_red_sandstone');
fill(colX[ci], ceilY - 1, colZ[cj], colX[ci] + 1, ceilY - 1, colZ[cj] + 1, 'chiseled_red_sandstone');
fill(colX[ci], walkY, colZ[cj], colX[ci] + 1, walkY, colZ[cj] + 1, 'smooth_red_sandstone');
}
}
// transept columns
var tcx = [34, 60], tk;
for (tk = 0; tk < 2; tk++) {
fill(tcx[tk], walkY, 45, tcx[tk] + 1, ceilY - 2, 46, 'cut_red_sandstone');
fill(tcx[tk], ceilY - 1, 45, tcx[tk] + 1, ceilY - 1, 46, 'chiseled_red_sandstone');
}
// ===== 5. WINDOWS — three registers, cut straight through =====
function cutWin(x1, y1, z1, x2, y2, z2) { fill(x1, y1, z1, x2, y2, z2, 'air'); }
// register 1 (Y7-9): tall ogee, 2 wide -> east & west nave walls
var wz;
for (wz = 36; wz <= 62; wz += 6) {
cutWin(NX1, 7, wz, NX1 + 4, 9, wz + 1);
cutWin(NX2 - 4, 7, wz, NX2, 9, wz + 1);
pb(NX1 + 1, 7, wz, 'orange_stained_glass'); pb(NX1 + 1, 7, wz + 1, 'orange_stained_glass');
pb(NX2 - 1, 7, wz, 'orange_stained_glass'); pb(NX2 - 1, 7, wz + 1, 'orange_stained_glass');
// ogee head
cutWin(NX1, 10, wz, NX1 + 4, 10, wz); cutWin(NX2 - 4, 10, wz + 1, NX2, 10, wz + 1);
}
// register 2 (Y11-12): keyhole on all four gable faces
var kx;
for (kx = 42; kx <= 53; kx += 5) {
cutWin(kx, 11, NZ1, kx, 12, NZ1 + 4);
cutWin(kx - 1, 12, NZ1, kx + 1, 12, NZ1 + 4);
cutWin(kx, 11, NZ2 - 4, kx, 12, NZ2);
cutWin(kx - 1, 12, NZ2 - 4, kx + 1, 12, NZ2);
}
var kz;
for (kz = 44; kz <= 49; kz += 5) {
cutWin(TX1, 11, kz, TX1 + 4, 12, kz);
cutWin(TX2 - 4, 11, kz, TX2, 12, kz);
}
// register 3 (Y14-15): small square lights, top tier
var sx2;
for (sx2 = 42; sx2 <= 53; sx2 += 4) {
cutWin(sx2, 14, NZ1 + 2, sx2, 14, NZ1 + 6);
cutWin(sx2, 14, NZ2 - 6, sx2, 14, NZ2 - 2);
}
var sz2;
for (sz2 = 38; sz2 <= 60; sz2 += 5) {
cutWin(NX1 + 2, 14, sz2, NX1 + 6, 14, sz2);
cutWin(NX2 - 6, 14, sz2, NX2 - 2, 14, sz2);
}
// ===== 6. DOOR, PORCH, FLIGHT INTO THE COURTYARD =====
fill(47, walkY, NZ2 - 4, 48, walkY + 2, NZ2 + 2, 'air');
fill(44, t1, NZ2 + 1, 51, floorY, NZ2 + 3, bodyPal); // porch platform, top = floorY
fill(44, t1, NZ2 + 4, 51, t1 + 1, NZ2 + 4, bodyPal);
fill(44, t1, NZ2 + 5, 51, t1, NZ2 + 5, bodyPal);
staircase(47, NZ2 + 6, courtWalk, walkY, 'north', { width: 4, material: 'red_sandstone_stairs', support: 'red_sandstone' });
ps(46, walkY + 1, NZ2 + 1, 'red_sandstone_wall');
ps(49, walkY + 1, NZ2 + 1, 'red_sandstone_wall');
pb(46, walkY + 2, NZ2 + 1, 'lantern');
pb(49, walkY + 2, NZ2 + 1, 'lantern');
// ===== 7. INTERIOR: ALTAR, CARPETS, CANDLES =====
fill(45, walkY, 35, 50, walkY, 36, 'polished_andesite'); // sanctuary dais (north)
fill(46, walkY + 1, 35, 49, walkY + 1, 35, 'chiseled_red_sandstone');
ps(46, walkY + 2, 35, 'candle[candles=4,lit=true]');
ps(49, walkY + 2, 35, 'candle[candles=4,lit=true]');
pb(47, walkY + 2, 35, 'gold_block');
pb(48, walkY + 2, 35, 'gold_block');
ps(47, walkY + 1, 37, 'lectern[facing=south]');
ps(44, walkY + 2, 34, 'yellow_wall_banner[facing=south]');
ps(51, walkY + 2, 34, 'red_wall_banner[facing=south]');
rug(46, walkY, 38, 3, 26, 'red', 'orange');
rug(36, walkY, 46, 24, 3, 'orange', 'red');
rug(43, walkY, 34, 4, 3, 'yellow', 'red');
// candle stands between the columns
var cs2;
for (cs2 = 0; cs2 < colZ.length; cs2++) {
pb(43, walkY, colZ[cs2], 'red_sandstone_wall');
ps(43, walkY + 1, colZ[cs2], 'candle[candles=3,lit=true]');
pb(52, walkY, colZ[cs2] + 1, 'red_sandstone_wall');
ps(52, walkY + 1, colZ[cs2] + 1, 'candle[candles=3,lit=true]');
}
// chests, pots, prayer benches
var bnz;
for (bnz = 40; bnz <= 62; bnz += 6) {
chairStair(45, walkY, bnz, 'dark_oak_stairs', 'north');
chairStair(46, walkY, bnz, 'dark_oak_stairs', 'north');
chairStair(49, walkY, bnz, 'dark_oak_stairs', 'north');
chairStair(50, walkY, bnz, 'dark_oak_stairs', 'north');
}
pb(33, walkY, 45, 'decorated_pot'); pb(62, walkY, 48, 'decorated_pot');
pb(33, walkY, 48, 'barrel'); pb(62, walkY, 45, 'chest[facing=west]');
// ceiling lanterns
var hl = [[44, 44], [51, 44], [44, 50], [51, 50], [47, 40], [47, 60], [36, 47], [59, 47]];
var hi;
for (hi = 0; hi < hl.length; hi++) {
ps(hl[hi][0], ceilY - 1, hl[hi][1], 'chain[axis=y]');
ps(hl[hi][0], ceilY - 2, hl[hi][1], 'lantern[hanging=true]');
}
// ===== 8. ROOF CROSS MOTIF (raised relief) =====
var ma, mb;
for (ma = -12; ma <= 12; ma++) {
for (mb = -3; mb <= 3; mb++) {
pb(48 + ma, motifY, 48 + mb, 'chiseled_red_sandstone');
pb(48 + mb, motifY, 48 + ma, 'chiseled_red_sandstone');
}
}
for (ma = -8; ma <= 8; ma++) {
for (mb = -1; mb <= 1; mb++) {
pb(48 + ma, motifY + 1, 48 + mb, 'cut_red_sandstone');
pb(48 + mb, motifY + 1, 48 + ma, 'cut_red_sandstone');
}
}
// ===== 9. MESA SURFACE: PILGRIM PATH, LAMPS, SCRUB =====
var gi;
for (gi = 26; gi <= 70; gi += 9) {
lampPost(CX1 - 3, mesaY + 1, gi, 5);
lampPost(CX2 + 3, mesaY + 1, gi, 5);
}
var ppz, ppx;
for (ppz = 20; ppz <= 34; ppz++) {
for (ppx = 3; ppx <= 9; ppx++) {
pb(ppx, Math.round(pad(ppx, ppz)), ppz, 'dirt_path');
}
}
var trs = [[16, 14], [12, 70], [22, 84], [58, 86], [84, 40], [80, 74], [40, 12], [70, 16]];
var ti2, ty2;
for (ti2 = 0; ti2 < trs.length; ti2++) {
if (!land(trs[ti2][0], trs[ti2][1])) continue;
ty2 = Math.round(pad(trs[ti2][0], trs[ti2][1])) + 1;
try { placeTree(trs[ti2][0], ty2, trs[ti2][1], 'acacia'); } catch (err) { }
}
var vx, vz, vy;
for (vx = 2; vx < 94; vx += 3) {
for (vz = 2; vz < 94; vz += 3) {
if (vx > 14 && vx < 82 && vz > 18 && vz < 78) continue;
if (!land(vx, vz)) continue;
if (noise2d('perlin', vx, vz, { freq: 0.15, seed: 23 }) > 0.3) {
vy = Math.round(pad(vx, vz)) + 1;
pb(vx, vy, vz, (vx + vz) % 4 === 0 ? 'dead_bush' : 'short_grass');
}
}
}
// rubble in the courtyard
fill(22, courtWalk, 26, 25, courtWalk + 1, 29, 'cobblestone');
fill(72, courtWalk, 68, 75, courtWalk + 1, 71, 'mossy_cobblestone');