// === BUILD PLAN ===
// Style: Icelandic torfbaer - turf-walled farmstead, timber-framed white gables facing SOUTH (+z)
// Footprint: three ranges of DIFFERENT width/depth side by side (deliberate asymmetry):
// W store (int x8-12, z24-33) | M hall+badstofa (int x15-21, z20-33) | E smithy (int x24-29, z22-33)
// turf walls 2 thick (x6-7 | 13-14 | 22-23 | 30-31), gables flush at z34, hill rises behind (north)
// Height: W eave y14, E eave y15, M: hearth room y11-14, loft floor y15, loft walk y16, ridge y21
//
// GROUND (top-down, z down, gables at bottom):
// ###########
// ... # hearth # ...
// ##### # (C) # ######
// # st#===# bench #==# smi# (=== passages z30)
// # # # S1 L # # # S1 flight north, L landing, S2 flight west
// ##D## ##W D W#### #W D##
//
// FRONT ELEVATION (south):
// /\
// /\ /ww\ /\
// / \ |----| / \
// | W D| |W D W| |W D|
// ===== stone plinth =====
//
// MATERIALS PLAN:
// base : cobble/mossy/andesite 2 courses WHY: stone-lined footing, damp band
// turf : HERRINGBONE strips mud_bricks vs packed_mud (+rooted_dirt) - WHY: klambra turf-block courses read as texture, not noise
// roof : grass_block/moss outer skin, rooted_dirt core, spruce rafters inside - WHY: living roof + visible structure from within
// gables : white_concrete boards, stripped_spruce corner posts, spruce barge boards, red mangrove doors - WHY: timber framing contrast
// Rooms: hearth room (fireplace+chimney, benches, table, loom, chests), badstofa loft (6 beds, chests, rug),
// storehouse (barrels, hay, hanging fish, cauldron), smithy (anvil, grindstone, blast furnace, bench)
// STAIR PLAN: hearth walk 11 -> loft walk 16 (delta 5): staircase north 11->14, landing, staircase west 14->16 (L-shape)
// === END PLAN ===
var padY = 10, floorY = 10, walk = 11, zG = 34;
// === TERRAIN ===
var hb = hills({ base: 9, amp: 2, scale: 0.05, seed: 21 });
var hill = function (x, z) { return hb(x, z) + Math.max(0, (17 - z) * 0.65); };
var land = blob(20, 25, 24, { irregularity: 0.35, seed: 31 });
var ground = flatten(hill, { x0: 3, z0: 17, x1: 36, z1: 46 }, padY, 6);
surface(land, ground, patches([{ block: 'grass_block', w: 65 }, { block: 'moss_block', w: 20 }, { block: 'coarse_dirt', w: 15 }], 0.07, 12));
// === MATERIAL FUNCTIONS ===
function stoneB() { var r = Math.random(); return r < 0.4 ? 'cobblestone' : (r < 0.75 ? 'mossy_cobblestone' : 'andesite'); }
function turfB(x, y, z) {
if (y <= walk + 1) return stoneB();
var band = Math.floor((y - walk - 2) / 2), dir = (band % 2 === 0) ? 1 : -1;
var v = (((x + z) * dir + y) % 4 + 4) % 4;
if (Math.random() < 0.12) return 'rooted_dirt';
return v < 2 ? 'mud_bricks' : 'packed_mud';
}
function skinB() { return Math.random() < 0.72 ? 'grass_block' : 'moss_block'; }
// === STRUCTURE ===
function range(x0, w, zi0, eave, floorFn) {
var xl = x0 - 2, xr = x0 + w + 1, zb = zi0 - 2, x, y, z, s;
for (y = walk; y < eave; y++) for (x = xl; x <= xr; x++) for (z = zb; z <= zG; z++) {
var inside = x >= x0 && x <= x0 + w - 1 && z >= zi0 && z <= zG - 1;
if (inside) pb(x, y, z, 'air');
else if (z === zG && x >= x0 - 1 && x <= x0 + w) pb(x, y, z, (x === x0 - 1 || x === x0 + w) ? 'stripped_spruce_log' : (y === walk ? stoneB() : 'white_concrete'));
else pb(x, y, z, turfB(x, y, z));
}
for (s = 0; ; s++) {
y = eave + s;
var a = xl + s, bb = xr - s;
if (a > bb) break;
var ca = x0 + s, cb = x0 + w - 1 - s, ga = x0 - 1 + s, gbx = x0 + w - s;
for (x = a; x <= bb; x++) for (z = zb - 1; z <= zG; z++) {
if (x >= ca && x <= cb && z >= zi0 && z <= zG - 1) { pb(x, y, z, 'air'); continue; }
if (z === zG && x >= ga && x <= gbx) { pb(x, y, z, (x === ga || x === gbx) ? 'spruce_planks' : 'white_concrete'); continue; }
var edge = (x === a || x === bb || s === 0 && z === zb - 1);
if (ca <= cb && (x === ca - 1 || x === cb + 1) && z >= zi0 && z < zG && z % 4 === 0) { pb(x, y, z, 'stripped_spruce_log[axis=y]'); continue; }
pb(x, y, z, (edge || x === a + 1 && s === 0) ? skinB() : 'rooted_dirt');
}
// top skin on the apex row and step tops
for (z = zb - 1; z <= zG; z++) { if (Math.random() < 0.12) pb(a, y + 1, z, 'fern'); }
}
// apex cap = grass
for (x = x0 - 2; x <= x0 + w + 1; x++) { }
for (x = x0; x <= x0 + w - 1; x++) for (z = zi0; z <= zG - 1; z++) pb(x, floorY, z, floorFn());
}
function mudF() { var r = Math.random(); return r < 0.6 ? 'packed_mud' : (r < 0.85 ? 'coarse_dirt' : 'gravel'); }
function plankF() { return Math.random() < 0.8 ? 'spruce_planks' : 'stripped_spruce_log[axis=z]'; }
function stoneF() { var r = Math.random(); return r < 0.5 ? 'stone_bricks' : (r < 0.8 ? 'cobblestone' : 'cracked_stone_bricks'); }
range(8, 5, 24, 14, mudF); // W storehouse (skemma)
range(24, 6, 22, 15, stoneF); // E smithy
range(15, 7, 20, 16, plankF); // M hall + badstofa (tallest, built last)
// stone plinth along the gable front
for (var px = 5; px <= 32; px++) pb(px, padY, zG + 1, stoneB());
// the apex of each roof: grass skin (ridge closed)
// (step loop already closes the ridge with a single block at the apex)
// === M: LOFT FLOOR + L-STAIR ===
fill(15, 15, 20, 21, 15, 33, 'spruce_planks');
var t1 = staircase(21, 31, walk, 14, 'north');
landing(20, 14, 26, 2, 2, 'spruce_planks');
var t2 = staircase(19, 26, 14, 16, 'west');
fill(20, 15, 26, 21, 15, 29, 'air'); // open the loft floor over landing + top of flight 1
for (var zz = 27; zz <= 30; zz++) pb(19, 16, zz, 'spruce_fence'); // loft railing
pb(20, 16, 30, 'spruce_fence'); pb(21, 16, 30, 'spruce_fence');
// === DOORS / WINDOWS / PASSAGES ===
function door(x) { ps(x, walk, zG, 'mangrove_door[facing=south,half=lower,hinge=left]'); ps(x, walk + 1, zG, 'mangrove_door[facing=south,half=upper,hinge=right]'); }
door(11); door(17); door(27);
function win(x, y) { pb(x, y, zG, 'glass_pane'); ps(x - 1, y, zG + 1, 'spruce_trapdoor[facing=south,open=true,half=bottom]'); }
function win2(x, y) { pb(x, y, zG, 'glass_pane'); }
win2(9, 12); win2(20, 12); win2(20, 13); win2(15, 12); win2(15, 13); win2(25, 12); win2(25, 13);
win2(18, 17); win2(18, 18); win2(10, 15); win2(26, 16);
fill(15, 14, zG, 21, 14, zG, 'spruce_planks'); // band at loft floor line
pb(14, 14, zG, 'stripped_spruce_log'); pb(22, 14, zG, 'stripped_spruce_log');
fill(13, walk, 30, 14, walk + 1, 30, 'air'); // passage store <-> hall
fill(22, walk, 30, 23, walk + 1, 30, 'air'); // passage hall <-> smithy
// flower boxes under hall windows
ps(20, walk, zG + 1, 'spruce_trapdoor[facing=south,open=true,half=bottom]');
// === HEARTH ROOM (M ground) ===
fill(17, walk, 20, 19, walk + 1, 20, 'cobblestone');
ps(18, walk, 20, 'campfire[lit=true]'); pb(18, walk + 1, 20, 'air');
fill(17, walk + 2, 20, 19, walk + 2, 20, 'mossy_cobblestone');
ps(17, walk + 3, 20, 'cobblestone_slab'); ps(19, walk + 3, 20, 'cobblestone_slab');
fill(18, walk + 2, 19, 18, 23, 19, 'cobblestone'); ps(18, 24, 19, 'cobblestone_wall');
fill(17, floorY, 21, 19, floorY, 22, 'stone_bricks'); // hearth stone apron
chairStair(16, walk, 22, 'spruce_stairs', 'east'); chairStair(20, walk, 22, 'spruce_stairs', 'west');
for (zz = 24; zz <= 26; zz++) { pb(17, walk, zz, 'spruce_fence'); pb(17, walk + 1, zz, 'spruce_pressure_plate'); }
chairStair(16, walk, 24, 'spruce_stairs', 'east'); chairStair(16, walk, 26, 'spruce_stairs', 'east');
chairStair(18, walk, 25, 'spruce_stairs', 'west');
ps(15, walk, 29, 'loom[facing=east]'); ps(15, walk, 31, 'chest[facing=east]'); pb(15, walk, 32, 'barrel');
pb(15, walk, 20, 'barrel'); pb(21, walk, 20, 'bookshelf'); pb(21, walk + 1, 20, 'bookshelf');
for (zz = 28; zz <= 32; zz++) for (var rx = 16; rx <= 18; rx++) pb(rx, walk, zz, zz % 2 === 0 ? 'brown_carpet' : 'red_carpet');
ps(18, 14, 23, 'lantern[hanging=true]'); ps(17, 14, 30, 'lantern[hanging=true]');
// === BADSTOFA (M loft, walk 16) ===
placeBed(16, 16, 22, 'red', 'north'); placeBed(16, 16, 25, 'white', 'north');
placeBed(16, 16, 29, 'blue', 'north'); placeBed(16, 16, 33, 'brown', 'north');
placeBed(20, 16, 22, 'green', 'north'); placeBed(20, 16, 33, 'yellow', 'north');
ps(20, 16, 24, 'chest[facing=west]'); pb(20, 16, 25, 'barrel');
for (zz = 21; zz <= 25; zz++) pb(18, 16, zz, 'white_carpet');
ps(18, 19, 23, 'lantern[hanging=true]'); ps(18, 19, 31, 'lantern[hanging=true]');
// === STOREHOUSE (W) ===
pb(8, walk, 24, 'barrel'); pb(8, walk, 25, 'barrel'); pb(8, walk + 1, 24, 'barrel');
fill(12, walk, 24, 12, walk + 1, 26, 'hay_block');
ps(8, walk, 28, 'chest[facing=east]'); ps(8, walk, 29, 'water_cauldron[level=3]');
pb(12, walk, 30, 'composter');
for (var hx = 9; hx <= 11; hx++) { ps(hx, 15, 27, 'chain[axis=y]'); pb(hx, 14, 27, 'dried_kelp_block'); }
ps(10, 15, 31, 'lantern[hanging=true]');
// === SMITHY (E) ===
ps(25, walk, 23, 'anvil[facing=east]'); ps(27, walk, 23, 'grindstone[face=floor,facing=south]');
ps(29, walk, 24, 'blast_furnace[facing=west]'); pb(29, walk, 25, 'smithing_table');
pb(24, walk, 27, 'crafting_table'); ps(24, walk, 28, 'chest[facing=east]');
pb(29, walk, 31, 'barrel'); pb(29, walk, 32, 'barrel'); ps(28, walk, 33, 'lantern');
ps(26, 16, 26, 'lantern[hanging=true]'); ps(27, 16, 31, 'lantern[hanging=true]');
// === YARD ===
function pathB() { var r = Math.random(); return r < 0.55 ? 'dirt_path' : (r < 0.8 ? 'gravel' : 'cobblestone'); }
var dx = [11, 17, 27], i, z2;
for (i = 0; i < 3; i++) for (z2 = zG + 1; z2 <= 42; z2++) pb(dx[i], padY, z2, pathB());
for (var x2 = 8; x2 <= 30; x2++) pb(x2, padY, 38, pathB());
// lamp posts
pb(15, walk, 36, 'spruce_fence'); pb(15, walk + 1, 36, 'spruce_fence'); pb(15, walk + 2, 36, 'lantern');
pb(29, walk, 36, 'spruce_fence'); pb(29, walk + 1, 36, 'spruce_fence'); pb(29, walk + 2, 36, 'lantern');
// fish drying rack (hjallur) - two A-frames + ridge pole
for (var ry = walk; ry <= walk + 2; ry++) { pb(32, ry, 40, 'spruce_fence'); pb(32, ry, 44, 'spruce_fence'); }
fill(32, walk + 3, 40, 32, walk + 3, 44, 'stripped_spruce_log[axis=z]');
for (z2 = 41; z2 <= 43; z2++) { ps(32, walk + 2, z2, 'chain[axis=y]'); pb(32, walk + 1, z2, 'dried_kelp_block'); }
// home-field turf wall (tungardur) with gate
for (x2 = 4; x2 <= 35; x2++) if (x2 < 16 || x2 > 18) pb(x2, walk, 46, x2 % 3 === 0 ? 'mossy_cobblestone_wall' : 'cobblestone_wall');
// sheep
function sheep(x, z, wool, head, facingX) {
pb(x, walk, z, wool); pb(x + facingX, walk, z, wool); pb(x, walk + 1, z, wool); pb(x + 2 * facingX, walk + 1, z, head);
pb(x + 2 * facingX, walk, z, wool);
}
sheep(6, 41, 'white_wool', 'white_terracotta', 1);
sheep(22, 43, 'white_wool', 'white_terracotta', -1);
sheep(25, 40, 'brown_wool', 'brown_terracotta', 1);
sheep(10, 44, 'black_wool', 'black_terracotta', 1);
sheep(34, 37, 'white_wool', 'white_terracotta', -1);
// wildflowers + lupine clumps
var fls = ['dandelion', 'oxeye_daisy', 'azure_bluet', 'fern', 'allium', 'allium'];
for (i = 0; i < 90; i++) {
var fx = 4 + Math.floor(Math.random() * 32), fz = 36 + Math.floor(Math.random() * 10);
if (fz === 38 || fx === 11 || fx === 17 || fx === 27 || fz === 46 || (fx === 32 && fz >= 40)) continue;
pb(fx, walk, fz, fls[i % fls.length]);
}