← Ancient and prehistory3D assetfogon/market-fountain
Fuente del zoco
Drag to turn it// «Fuente del zoco» · propio
// An octagonal sandstone basin full of teal water with a pale rim, and in the middle a carved stone column that widens into a shallow bowl at the top.
// The market's fountain: an octagonal sandstone basin full of teal water with a pale rim, and a carved column in
// the middle that widens into a shallow bowl.
const stone = ["#a37c4b", "#b38c57", "#c19a64", "#cda870", "#d8b57e"];
const mortar = "#84653c";
const trim = ["#d4bd8c", "#e0cb9c", "#ebd8ad", "#f4e6c4"];
const water = ["#27626e", "#2f7482", "#3d8b98", "#63abb5"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const C = 23.5;
const oct = (x, y) => Math.max(Math.abs(x - C), Math.abs(y - C), (Math.abs(x - C) + Math.abs(y - C)) * 0.7071);
const hash = (a, b) => {
const s = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;
return s - Math.floor(s);
};
// The basin.
for (let x = 0; x < 48; x++)
for (let y = 0; y < 48; y++) {
const d = oct(x, y);
if (d > 20.6) continue;
for (let z = 0; z <= 10; z++) {
if (z >= 9) {
// The rim: pale, wider than the wall.
if (d > 14.6) set(x, y, z, (Math.round(Math.atan2(y - C, x - C) * 40) % 9 === 0 ? "#bfa878" : trim[clampi((z === 10 ? 2 : 1) + (d < 16 && z === 10 ? 1 : 0) - (rand() < 0.14 ? 1 : 0), 0, 3)]));
continue;
}
if (d > 19.4) continue;
if (d > 16.2) {
// The wall: courses of blocks.
const u = Math.round((Math.atan2(y - C, x - C) + Math.PI) * 19);
const row = Math.floor(z / 3);
const k = Math.floor((u + row * 4) / 8);
const line = z % 3 === 2 || (u + row * 4) % 8 === 0;
set(x, y, z, line ? mortar : stone[clampi(1 + Math.floor(hash(k, row) * 3) + (z > 5 ? 1 : 0) - (rand() < 0.12 ? 1 : 0), 0, 4)]);
} else if (z <= 1) set(x, y, z, stone[1]);
else if (z <= 7) {
// Water, with paler ripples around the column.
const r = Math.hypot(x - C, y - C);
const ripple = z === 7 && (Math.round(r) % 5 === 0 || rand() < 0.06);
set(x, y, z, ripple ? water[3] : water[clampi(1 + (hash(x >> 1, y >> 1) > 0.6 ? 1 : 0), 0, 2)]);
}
}
}
// The column: its radius at each height.
const profile = [[7, 5.2], [9, 5.2], [10, 4.2], [12, 3.4], [13, 2.7], [26, 2.5], [27, 3.2], [28, 4.3], [29, 5.8], [30, 7.4], [31, 8.8], [32, 9.4], [33, 9.4]];
function radiusAt(z) {
for (let i = 0; i < profile.length - 1; i++) {
const [z0, r0] = profile[i], [z1, r1] = profile[i + 1];
if (z >= z0 && z <= z1) return r0 + ((r1 - r0) * (z - z0)) / (z1 - z0 || 1);
}
return 0;
}
for (let z = 7; z <= 33; z++) {
const r = radiusAt(z);
for (let x = Math.floor(C - r - 1); x <= Math.ceil(C + r + 1); x++)
for (let y = Math.floor(C - r - 1); y <= Math.ceil(C + r + 1); y++) {
const d = Math.hypot(x - C, y - C);
if (d > r) continue;
if (z >= 32 && d < r - 1.6) {
// The bowl holds water.
if (z === 32) set(x, y, z, Math.round(d) % 3 === 0 ? water[3] : water[2]);
continue;
}
let tone = z >= 27 ? 2 : z < 13 ? 1 : 2;
if (x < C && y < C) tone++;
if (x > C + 1 && y > C + 1) tone--;
if (z === 13 || z === 26 || z === 10) tone = 0;
if (rand() < 0.1) tone--;
set(x, y, z, trim[clampi(tone, 0, 3)]);
}
}
// Flutes carved down the shaft, a knob on top, and four thin streams falling from the bowl.
for (let z = 15; z <= 24; z++) for (const [dx, dy] of [[-3, 0], [3, 0], [0, -3], [0, 3]]) set(Math.round(C + dx), Math.round(C + dy), z, "#bfa878");
box(23, 23, 33, 24, 24, 35, trim[2]);
box(23, 23, 36, 24, 24, 36, trim[3]);
for (const [dx, dy] of [[-10, 0], [10, 0], [0, -10], [0, 10]]) for (let z = 8; z <= 31; z++) if (z % 5 !== 0) set(Math.round(C + dx), Math.round(C + dy), z, z % 2 ? "#9fd6dc" : "#c6ecf0");import { draw } from "./assets/voxel";
import { marketFountain } from "./assets/market-fountain";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, marketFountain, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: its longest side, in px
// angle: turn on the floor, in radians
// t: seconds; if it moves, that animates it# In a terminal, in the game's folder
fogon assets add market-fountain
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["market-fountain"] })
# It lands in client/assets/market-fountain.ts
# https://fogon.gg/object/market-fountain