← Medieval3D assetfogon/celda-de-mazmorra
Celda de mazmorra
Drag to turn it// «Celda de mazmorra» · gpt-6-sol (medium)
// A dungeon cell: a cube of dark grey mossy stone walls on three sides (back, left, right) and floor, with the front side closed by thick black iron bars and a barred door with a big lock, a pile of straw and a wooden bucket inside, and a chain with a shackle hanging from the back wall.
const stone = ["#746f67", "#827c71", "#938b7d", "#625f59"];
const mortar = "#514e49";
const moss = ["#586443", "#69734b", "#434f3d"];
const iron = "#24272a";
const ironEdge = "#424449";
const ironLight = "#626266";
const wood = ["#69452c", "#795237", "#89613e", "#563a29"];
// Solid foundation, with broad, uneven flagstones.
box(5, 5, 0, 42, 42, 1, "#504e49");
box(5, 5, 2, 42, 42, 2, mortar);
for (let x = 6; x <= 41; x += 6) {
for (let y = 6; y <= 41; y += 6) {
const c = stone[Math.floor(rand() * 3)];
box(x, y, 2, Math.min(x + 4, 41), Math.min(y + 4, 41), 2, c);
if (rand() < 0.35) set(x + 1, y + 1, 2, "#a19887");
if (rand() < 0.25) set(x + 4, y + 3, 2, moss[0]);
}
}
// Three thick stone walls. The front remains open for the ironwork.
box(5, 8, 3, 8, 42, 34, "#69665f");
box(39, 8, 3, 42, 42, 34, "#69665f");
box(5, 39, 3, 42, 42, 34, "#69665f");
// Courses and staggered joints on the surfaces facing the cell.
for (let z = 3; z <= 34; z++) {
const course = Math.floor((z - 3) / 4);
const seamZ = (z - 3) % 4 === 3;
for (let x = 9; x <= 38; x++) {
const seam = (x + (course % 2) * 4) % 8 === 0;
let c = seamZ || seam ? mortar : stone[(Math.floor(x / 8) + course) % 3];
if (!seamZ && !seam && rand() < 0.035) c = moss[Math.floor(rand() * 3)];
set(x, 39, z, c);
}
for (let y = 9; y <= 38; y++) {
const seam = (y + (course % 2) * 4) % 8 === 0;
for (const x of [8, 39]) {
let c = seamZ || seam ? mortar : stone[(Math.floor(y / 8) + course + 1) % 3];
if (!seamZ && !seam && rand() < 0.045) c = moss[Math.floor(rand() * 3)];
set(x, y, z, c);
}
}
}
// Chipped cornerstones and moss collecting where the walls meet the floor.
for (let z = 3; z <= 34; z += 4) {
for (const x of [6, 40]) {
set(x, 39, z, "#a09888");
set(x, 40, z, "#625e56");
}
}
for (let i = 0; i < 105; i++) {
const x = 9 + Math.floor(rand() * 30);
const y = 10 + Math.floor(rand() * 29);
if (x < 13 || x > 35 || y > 34) {
const z = 3 + Math.floor(rand() * 4);
if (get(x, y, z)) set(x, y, z, moss[Math.floor(rand() * 3)]);
}
}
// Straw heap, low and broad enough to see between the bars.
ellipsoid(18, 21, 3, 8, 6, 2, "#a88140");
ellipsoid(18, 20, 4, 6, 4, 2, "#c29a50");
ellipsoid(17, 19, 5, 4, 3, 1, "#d8b769");
for (let i = 0; i < 95; i++) {
const x = 11 + Math.floor(rand() * 15);
const y = 15 + Math.floor(rand() * 12);
const z = 3 + Math.floor(rand() * 3);
const length = 2 + Math.floor(rand() * 4);
const color = ["#ddbd72", "#ae803b", "#e4c77d"][Math.floor(rand() * 3)];
line(x, y, z, x + (rand() < 0.5 ? length : -length),
y + (rand() < 0.5 ? 1 : -1), Math.max(3, z - 1), 0, color);
}
// A stout wooden bucket with hoops, an open dark mouth, and a handle.
const bx = 33, by = 20;
for (let z = 3; z <= 10; z++) {
for (let dx = -4; dx <= 4; dx++) {
for (let dy = -4; dy <= 4; dy++) {
const d = Math.sqrt(dx * dx + dy * dy);
if (d <= 4 && (z < 10 || d >= 2.7)) {
const plank = Math.floor((Math.atan2(dy, dx) + Math.PI) * 2.5);
set(bx + dx, by + dy, z, wood[(plank + (dy < 0 ? 1 : 0)) % wood.length]);
}
}
}
}
for (let dx = -2; dx <= 2; dx++) {
for (let dy = -2; dy <= 2; dy++) {
if (dx * dx + dy * dy <= 6) set(bx + dx, by + dy, 9, "#342e29");
}
}
for (const z of [4, 8]) {
for (let dx = -4; dx <= 4; dx++) {
for (let dy = -4; dy <= 4; dy++) {
const d = Math.sqrt(dx * dx + dy * dy);
if (d >= 3.5 && d <= 4.5) set(bx + dx, by + dy, z, iron);
}
}
}
for (const dx of [-4, 4]) set(bx + dx, by, 8, ironLight);
line(29, 20, 8, 30, 20, 13, 0, ironEdge);
line(30, 20, 13, 36, 20, 13, 0, ironEdge);
line(36, 20, 13, 37, 20, 8, 0, ironEdge);
// Back-wall anchor, hanging chain links, and an open shackle.
box(22, 37, 29, 26, 38, 32, iron);
box(23, 36, 30, 25, 36, 31, ironEdge);
for (const x of [23, 25]) set(x, 36, 31, ironLight);
for (let z = 26; z >= 15; z -= 3) {
const y = (Math.floor((26 - z) / 3) % 2) ? 36 : 37;
set(24, y, z + 2, ironEdge);
set(23, y, z + 1, iron);
set(25, y, z + 1, iron);
set(24, y, z, ironEdge);
}
set(24, 36, 14, ironLight);
for (let a = 0; a <= Math.PI * 1.8; a += 0.12) {
set(24 + Math.round(3 * Math.cos(a)), 36,
11 + Math.round(3 * Math.sin(a)), ironEdge);
}
box(20, 35, 10, 21, 37, 12, iron);
set(20, 35, 11, ironLight);
// Massive front stone jambs and overhead lintel.
box(5, 5, 3, 8, 9, 35, "#777168");
box(39, 5, 3, 42, 9, 35, "#777168");
box(5, 5, 33, 42, 9, 36, "#746e65");
for (let x = 5; x <= 42; x++) {
if (x % 7 === 4) box(x, 5, 33, x, 5, 36, mortar);
else if (x % 7 === 5) set(x, 5, 35, "#a19989");
}
for (const x of [6, 40]) {
for (let z = 5; z <= 32; z += 6) {
set(x, 5, z, "#9a9283");
set(x + 1, 5, z + 2, mortar);
}
}
// Fixed grating either side of the doorway.
for (const x of [9, 12, 35, 38]) {
box(x, 5, 3, x + 1, 6, 32, iron);
box(x, 4, 5, x, 4, 30, ironEdge);
set(x, 4, 10, ironLight);
set(x, 4, 24, ironLight);
}
for (const z of [5, 17, 30]) {
box(9, 5, z, 14, 6, z + 1, iron);
box(33, 5, z, 38, 6, z + 1, iron);
}
box(14, 5, 3, 15, 7, 32, "#171b1e");
box(32, 5, 3, 33, 7, 32, "#171b1e");
for (let z = 7; z <= 29; z += 5) {
set(14, 4, z, ironLight);
set(33, 4, z, ironLight);
}
// The door is one hinged, swinging part.
part("barred door", [16, 5, 16]);
for (const x of [16, 19, 22, 25, 28, 31]) {
box(x, 5, 4, x + 1, 6, 31, iron);
box(x, 4, 6, x, 4, 29, ironEdge);
}
for (const z of [4, 17, 30]) {
box(16, 5, z, 32, 6, z + 1, "#171b1e");
box(17, 4, z + 1, 31, 4, z + 1, ironEdge);
for (const x of [19, 22, 25, 28, 31]) set(x, 3, z + 1, ironLight);
}
for (const z of [7, 26]) {
box(15, 4, z, 17, 7, z + 2, ironEdge);
set(16, 3, z + 1, ironLight);
}
// Oversized iron lock plate, brass edging, and a clearly visible keyhole.
box(27, 2, 13, 33, 4, 21, "#aa8542");
box(28, 1, 14, 32, 1, 20, iron);
for (const x of [28, 32]) {
for (const z of [14, 20]) set(x, 0, z, "#c2a15c");
}
box(29, 0, 17, 31, 0, 18, "#b99b5c");
set(30, -1, 17, "#17191b");
set(30, -1, 16, "#17191b");
animate("barred door", { type: "swing", axis: "z", speed: 1, amplitude: 0.3 });
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { celdaDeMazmorra } from "./assets/celda-de-mazmorra";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, celdaDeMazmorra, 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 celda-de-mazmorra
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["celda-de-mazmorra"] })
# It lands in client/assets/celda-de-mazmorra.ts
# https://fogon.page/object/celda-de-mazmorra