Brick press: clay lumps into green bricks that fire into Bricks (t28)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,18 @@ above, including:
|
||||
machines (Grinder 0.25 grains/tick, $60; Saw 0.5, $90). In a vertical stack only the top block
|
||||
takes input and the result passes down through the rest, so a Saw on a Grinder cuts stone and
|
||||
grinds everything else. Partial brick counts are not saved.
|
||||
After the owner played it: the Refiner and Stone cutter code is gone (an old save that still has
|
||||
one loads without it and refunds its price). Grinders draw as a pair of grinding wheels and
|
||||
Saws as a round blade, turning while busy. The Saw also cuts wood chunks into Planks (2 build a
|
||||
wood wall). Its stone output is now called a Stone block, so that only fired clay is a brick.
|
||||
Items piling up under a block stay a thing to build around (a belt or an open drop), and the
|
||||
Saw's text says so.
|
||||
|
||||
- **Clay bricks come from a Brick press (t28, 2026-10-24).** A hopper block like the Saw: every
|
||||
8 clay lumps on top become a Green brick below, and a Green brick fires into a Brick above about
|
||||
900°C (any fire). 2 Bricks build a brick wall block; builders order them. The owner found it odd
|
||||
that clay bricks (first planned as a mold) and stone bricks would be made in different ways, and
|
||||
chose a press over a heated kiln block or a mold. Loose clay still fires into brick rubble.
|
||||
- **The bag is the vacuum's control panel (t6).** Each bag row has separate pick-up and blow
|
||||
marks; a chip on the tool card sets pick-up to everything, only marked, or the same as the
|
||||
first click; R over a grain toggles its pick-up mark. The owner found the shared ticks confusing.
|
||||
|
||||
+9
-9
@@ -196,15 +196,15 @@ Deepgrain Foundry: simulation core (src/sim/). No DOM anywhere in src/sim/: plai
|
||||
- functions: rnd, mulberry32, hash2
|
||||
- variables: RS, PH_EMPTY, PH_SOLID, PH_POWDER, PH_LIQUID, PH_GAS, PH_ITEM
|
||||
|
||||
### src/sim/materials.js (162 lines)
|
||||
### src/sim/materials.js (167 lines)
|
||||
Material ids, the material table (def), per-material property arrays, cell flags and part ids, and drill/tank tiers.
|
||||
- functions: def, metalFamily
|
||||
- variables: EMPTY, GRASS, DIRT, LDIRT, SAND, GRAVEL, CLAY, STONE, GRANITE, BASALT, NMAT, MD, PH, DENS, KC, ICAP, CASTMETAL, METAL_TIER, SOLIDMETAL, F_NAT, F_CAST, F_BURN, P_NONE, P_TU, P_TD, P_TL, P_TR, P_GRATE, P_GOPEN, P_WHEEL, P_INTAKE, P_FILTER, P_PIPE, TDX, TDY, BIT_TIERS, TANK_TIERS, REACH
|
||||
- variables: EMPTY, GRASS, DIRT, LDIRT, SAND, GRAVEL, CLAY, STONE, GRANITE, BASALT, NMAT, MD, FIRETO, PH, DENS, KC, ICAP, CASTMETAL, METAL_TIER, SOLIDMETAL, F_NAT, F_CAST, F_BURN, P_NONE, P_TU, P_TD, P_TL, P_TR, P_GRATE, P_GOPEN, P_WHEEL, P_INTAKE, P_FILTER, P_PIPE, TDX, TDY, BIT_TIERS, TANK_TIERS, REACH
|
||||
|
||||
### src/sim/pieces.js (139 lines)
|
||||
### src/sim/pieces.js (141 lines)
|
||||
Everything the player can build (PIECES): blocks, machines and molds, with costs and descriptions; filter settings; wall materials and their cost.
|
||||
- functions: isPipeCode, filterable, cleanFilterCfg, filterRec, filterPassAt, filterInfo, sameFilter, wallCost
|
||||
- variables: BS, BP_WALL, BP_BELT, BP_TUBE, BP_SHAFT, BP_GRATE, BP_GATE, BP_FILTER, BP_PIPE, BP_PUMP, BP_OUTLET, BP_GRIND, BP_SAW, filterCfg, WALL_OF, WALL_LIST, BAR_OF, GRAINS_PER_BAR, POWER_FREE, CASH, PIECES, PIECE_BY_ID, PIECE_BY_CODE, BELT_POWER, TUBE_POWER, FAN_POWER, WHEEL_K, ENGINE_K, MOLDS
|
||||
- variables: BS, BP_WALL, BP_BELT, BP_TUBE, BP_SHAFT, BP_GRATE, BP_GATE, BP_FILTER, BP_PIPE, BP_PUMP, BP_OUTLET, BP_GRIND, BP_SAW, BP_PRESS, filterCfg, WALL_OF, WALL_LIST, BAR_OF, GRAINS_PER_BAR, POWER_FREE, CASH, PIECES, PIECE_BY_ID, PIECE_BY_CODE, BELT_POWER, TUBE_POWER, FAN_POWER, WHEEL_K, ENGINE_K, MOLDS
|
||||
|
||||
### src/sim/economy.js (152 lines)
|
||||
Money, prices, market saturation, the trade dock, buyer and builder orders.
|
||||
@@ -241,7 +241,7 @@ Machines: the power network, footprints, placing and removing machines.
|
||||
- functions: markPow, partLost, rebuildPower, netSat, evictCells, cellBuildable, machineFootprint, canPlaceMachine, addMachine, removeMachine
|
||||
- variables: nextPowerBuild
|
||||
|
||||
### src/sim/processors.js (108 lines)
|
||||
### src/sim/processors.js (113 lines)
|
||||
Processing: Grinder and Saw blocks, and the Silo.
|
||||
- functions: isProcCode, rebuildProcessors, procBottom, procSlot, procFeed, procBlocksTick, siloTick, siloFull
|
||||
- variables: REFINE, REFINE_SAND, CUT_PER_BRICK, SAW_CUTS, procState, procBlocks, procDirty, SILO_CAP, SILO_RATE
|
||||
@@ -269,7 +269,7 @@ Molds: cavities for castings; ingot troughs empty themselves below. Removal retu
|
||||
- functions: moldCellsAt, canPlaceMold, newMoldRecord, addMold, castMix, cavityState, troughState, clearCavity, moldPlugCells, rakeAbove, furnaceJunkHint, unplugMold, ejectIngot, checkMolds, moldAt, tally, collectMold, removeMold
|
||||
- variables: DROSS, grains, barWord
|
||||
|
||||
### src/sim/items.js (200 lines)
|
||||
### src/sim/items.js (203 lines)
|
||||
Bars and other loose objects (ents), and the bag: adding, taking, costs and refunds.
|
||||
- functions: entSolidCell, entFreeAt, entMark, spawnBar, removeEnt, entTubeAt, entTubeFree, entTubeMove, entTubeEnter, entTubeTick, entTick, entsInCircle, bagAdd, bagTake, giveOrDrop, refundAt, canAfford, payCost, fmtMoney, costText, needText
|
||||
- variables: BAR_W, BAR_H, entCurM, droppedLast
|
||||
@@ -348,7 +348,7 @@ Scale colour without changing the smooth-look class.
|
||||
- functions: fogColor, drawWorld
|
||||
- variables: TUBE_CLASS
|
||||
|
||||
### src/render/machines.js (207 lines)
|
||||
### src/render/machines.js (212 lines)
|
||||
Machine overlays: fans, engines, silo and the rest, drawn on top of the world.
|
||||
- functions: cellRect, drawHazardRims, drawMachines, drawProcBlocks, drawSilo, drawSiloPixel
|
||||
|
||||
@@ -399,7 +399,7 @@ The notebook (N): milestones, market, wallet, blueprints, controls.
|
||||
The tool hotbar and what is selected.
|
||||
- functions: renderHotbar, toolId, steering, modShift, grainAt, selectTool, bagMaterials, blowList, blowAllList, blowingAll, piece
|
||||
|
||||
### src/ui/build-menu.js (102 lines)
|
||||
### src/ui/build-menu.js (103 lines)
|
||||
The build menu along the bottom: categories, piece tiles and their icons.
|
||||
- functions: pieceIcon, catOf, selectBuildCat, cycleBuildCat, buildVariantChips, renderBuildBar, setupBuildBar
|
||||
- variables: BUILD_CATS, BUILD_ORDER, PIECE_ICONS, lastBuildKey, lastBuildMenu
|
||||
@@ -409,7 +409,7 @@ The selected tool and piece: R / Q / E, drill width, filter picker, the selectio
|
||||
- functions: pieceUsesWall, setDrillWidth, tuneUnderCursor, cycleItem, cycleWall, rotate, toggleBlow, pickFilterUnderCursor, toggleFilterMat, setBrush, pieceV, pieceExtra, filterChoices, matList, filterParts, filterSentence, applyFilterRun, openFilterPicker, openWallPicker, filterBlockAt, chipCost, pieceCostNow, renderSelCard, renderBag
|
||||
- variables: lastBagKey
|
||||
|
||||
### src/ui/info.js (173 lines)
|
||||
### src/ui/info.js (174 lines)
|
||||
Discovery cards, hover info (I) and the cursor label.
|
||||
- functions: showCard, howText, discoveryCard, reactionsOf, hoverInfo, renderInfo, drawCursorLabel
|
||||
|
||||
|
||||
@@ -4,6 +4,19 @@ What agents have done, newest first. Add an entry for every piece of work: the d
|
||||
note or request it was for, what changed, the files touched, the tests run, and anything left
|
||||
open or not verified. Keep each entry short; the git history has the details.
|
||||
|
||||
## 2026-10-24: t4 follow-ups and t28 Brick press (Claude Code, Codex)
|
||||
|
||||
- `9739ca0`: Refiner and Stone cutter code removed; `save.js` skips unknown machine types on load
|
||||
and refunds a refiner ($120) or cutter ($90). Their old t_pipes/t_stone checks now use blocks.
|
||||
- `f5e5591`: `drawProcBlocks` (`render/machines.js`) draws Grinder wheels and the Saw blade over a
|
||||
plain housing texture; turns while busy, no `rnd()`.
|
||||
- `08d2d65`: `PLANK` item; the Saw cuts `LWOOD` too (`SAW_CUTS`, per-material `cut` counts).
|
||||
"Stone brick" is "Stone block" in player text. Saw text explains the pile-up under it.
|
||||
- t28: `BP_PRESS`/`PRESSB`, `GREENB` and `BARBR` items, `FIRETO` (items.js fires a hot green
|
||||
brick into a Brick). Machines tab, hover, notebook, milestone hint.
|
||||
- Tests: `run_all.py --browser` passed after each commit (t_smooth's flake rerun alone).
|
||||
Screenshots `shots/t4-wheels{,-smooth}.png`, `shots/t28-press.png`.
|
||||
|
||||
## 2026-10-24: t4: Grinder and Saw hopper blocks (Claude Code, Codex)
|
||||
|
||||
- New block pieces `grinder`/`saw` (`BP_GRIND`/`BP_SAW`, materials `GRINDER`/`SAWB`, NMAT 97).
|
||||
|
||||
@@ -90,7 +90,12 @@ function drawProcBlocks() {
|
||||
const radius = sw * (saw ? 0.38 : 0.22), teeth = saw ? 10 : 6;
|
||||
ctx.save();
|
||||
ctx.lineWidth = Math.max(1, sw * 0.025);
|
||||
for (let wheel = 0; wheel < (saw ? 1 : 2); wheel++) {
|
||||
if (blockP[b] === BP_PRESS) {
|
||||
const offset = busy ? (1 - Math.cos(tick * 0.3)) * sw * 0.12 : 0;
|
||||
ctx.fillStyle = '#caa488'; ctx.fillRect(sx + sw * 0.27, sy + sw * 0.76, sw * 0.46, sw * 0.16);
|
||||
ctx.fillStyle = '#7d8996'; ctx.fillRect(sx + sw * 0.45, sy, sw * 0.1, sw * 0.4 + offset);
|
||||
ctx.fillStyle = '#b9c0c8'; ctx.fillRect(sx + sw * 0.12, sy + sw * 0.4 + offset, sw * 0.76, sw * 0.12);
|
||||
} else for (let wheel = 0; wheel < (saw ? 1 : 2); wheel++) {
|
||||
const cx = sx + sw * (saw ? 0.5 : wheel ? 0.73 : 0.27), cy = sy + sw * 0.5;
|
||||
const a = wheel ? -angle : angle;
|
||||
ctx.fillStyle = saw ? '#b9c0c8' : '#8a8f96'; ctx.strokeStyle = '#444b54';
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ function drawWorld() {
|
||||
}
|
||||
else if (m === GATE) { if ((x & 1) === 0 && (y & 3) !== 0) { r -= 40; g -= 24; b -= 20; } }
|
||||
else if (m === CUTST) { const lx = x & 3, ly = y & 3; if (ly === 1 || ly === 3 || lx === (ly < 2 ? 3 : 1)) { r -= 34; g -= 33; b -= 30; } else if (ly === 0 || ly === 2) { r += 10; g += 10; b += 9; } }
|
||||
else if (m === GRINDER || m === SAWB) {
|
||||
else if (m === GRINDER || m === SAWB || m === PRESSB) {
|
||||
const lx = x & 3, ly = y & 3, frame = lx === 0 || lx === 3 || ly === 0 || ly === 3;
|
||||
r = frame ? 96 : 38; g = frame ? 102 : 42; b = frame ? 112 : 50;
|
||||
}
|
||||
|
||||
+3
-3
@@ -26,7 +26,7 @@ function placeBlock(code, v, bx, by, free, extra) {
|
||||
if (code === BP_WALL) setCell(i, WALL_OF[v], AMB[y], 0);
|
||||
else if (code === BP_BELT) { setCell(i, v === 0 ? BELTL : BELTR, AMB[y], 0); markPow(i, true); }
|
||||
else if (code === BP_SHAFT) { setCell(i, SHAFT, AMB[y], 0); markPow(i, true); }
|
||||
else if (isProcCode(code)) setCell(i, code === BP_GRIND ? GRINDER : SAWB, AMB[y], 0);
|
||||
else if (isProcCode(code)) setCell(i, code === BP_GRIND ? GRINDER : code === BP_PRESS ? PRESSB : SAWB, AMB[y], 0);
|
||||
else if (code === BP_GATE) setCell(i, GATE, AMB[y], 0);
|
||||
else if (code === BP_GRATE) { part[i] = P_GRATE; wakeXY(x, y); }
|
||||
else if (code === BP_TUBE) { part[i] = [P_TU, P_TR, P_TD, P_TL][v & 3]; markPow(i, true); wakeXY(x, y); }
|
||||
@@ -53,7 +53,7 @@ function blockIntegrity(b) {
|
||||
if (code === BP_WALL) { if (PH[m] === PH_SOLID && !(flags[i] & F_NAT) && !PARTMAT[m]) n++; }
|
||||
else if (code === BP_BELT) { if (m === BELTL || m === BELTR) n++; }
|
||||
else if (code === BP_SHAFT) { if (m === SHAFT) n++; }
|
||||
else if (isProcCode(code)) { if (m === (code === BP_GRIND ? GRINDER : SAWB)) n++; }
|
||||
else if (isProcCode(code)) { if (m === (code === BP_GRIND ? GRINDER : code === BP_PRESS ? PRESSB : SAWB)) n++; }
|
||||
else if (code === BP_GATE) { if (m === GATE || p === P_GOPEN) n++; }
|
||||
else if (code === BP_GRATE) { if (p === P_GRATE) n++; }
|
||||
else if (code === BP_TUBE) { if (p >= P_TU && p <= P_TR) n++; }
|
||||
@@ -83,7 +83,7 @@ function removeBlock(bx, by) {
|
||||
if (p === P_PIPE) { part[i] = 0; wakeIdx(i); n++; }
|
||||
else if (m === PIPE) { setCell(i, EMPTY, temp[i], 0); n++; }
|
||||
} else if (code === BP_BELT || code === BP_SHAFT || code === BP_GATE || isProcCode(code)) {
|
||||
if (m === BELTL || m === BELTR || m === SHAFT || m === GATE || m === GRINDER || m === SAWB) { setCell(i, EMPTY, temp[i], 0); markPow(i, false); n++; }
|
||||
if (m === BELTL || m === BELTR || m === SHAFT || m === GATE || m === GRINDER || m === SAWB || m === PRESSB) { setCell(i, EMPTY, temp[i], 0); markPow(i, false); n++; }
|
||||
if (p === P_GOPEN) { part[i] = 0; n++; wakeIdx(i); }
|
||||
} else if (p) { part[i] = 0; markPow(i, false); wakeIdx(i); n++; }
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ const PRICE = new Float32Array(NMAT);
|
||||
for (const [m, v] of [
|
||||
[SAND, 0.1], [LCLAY, 0.2], [LWOOD, 0.3], [ACORN, 0.5], [COAL, 0.5], [RGRAN, 0.2], [RBAS, 0.4],
|
||||
[CUORE, 1], [FEORE, 1.6], [SNORE, 2], [ZNORE, 2.2], [AGORE, 6], [AUORE, 14],
|
||||
[CHARCOAL, 1.2], [RBRICK, 0.8], [CULLET, 1.2], [BARGL, 14], [RSTONE, 0.02], [GRAVEL, 0.03], [BARSB, 0.6], [PLANK, 2.4],
|
||||
[CHARCOAL, 1.2], [RBRICK, 0.8], [CULLET, 1.2], [BARGL, 14], [RSTONE, 0.02], [GRAVEL, 0.03], [BARSB, 0.6], [PLANK, 2.4], [GREENB, 2], [BARBR, 9],
|
||||
[SCRCU, 3], [SCRFE, 5], [SCRST, 11], [SCRSN, 3.5], [SCRZN, 3.5], [SCRAG, 18], [SCRAU, 40], [SCRBZ, 8], [SCRBS, 7],
|
||||
[BARCU, 40], [BARFE, 75], [BARST, 160], [BARSN, 50], [BARZN, 50], [BARAG, 220], [BARAU, 480], [BARBZ, 110], [BARBS, 95],
|
||||
]) PRICE[m] = v;
|
||||
@@ -73,7 +73,7 @@ const STANDING = ['Local buyers', 'County buyers', 'Regional buyers', 'National
|
||||
function standing() { return Math.min(STANDING.length - 1, Math.floor(ordersDone / 4)); }
|
||||
// Builders buy the cheap bulk stuff (rubble, gravel, sand, stone blocks, planks) in big lots at a few
|
||||
// times the market price, so waste rock earns a little. [what, smallest lot, largest lot]
|
||||
const BUILD_GOODS = [[RSTONE, 400, 1500], [GRAVEL, 300, 1000], [SAND, 300, 900], [BARSB, 20, 80], [PLANK, 20, 80]];
|
||||
const BUILD_GOODS = [[RSTONE, 400, 1500], [GRAVEL, 300, 1000], [SAND, 300, 900], [BARSB, 20, 80], [PLANK, 20, 80], [BARBR, 20, 80]];
|
||||
function makeBuildersOrder() {
|
||||
const cands = BUILD_GOODS.filter(([m]) => seen[m] && !orders.some(o => o.m === m));
|
||||
if (!cands.length) return null;
|
||||
|
||||
@@ -136,6 +136,9 @@ function entTick() {
|
||||
// heat: the bar tends toward the temperature around it
|
||||
const T = temp[Math.min(H - 1, cy + 1) * W + Math.min(W - 1, cx + 1)];
|
||||
e.T += (T - e.T) * 0.04;
|
||||
if (FIRETO[e.m] && e.T >= 880 && rnd() < 0.004 + (e.T - 880) * 0.00012) {
|
||||
e.m = FIRETO[e.m]; discover(e.m, e.ix, e.iy, GREENB, 'fire', 880);
|
||||
}
|
||||
if (e.T >= MELT[e.m]) {
|
||||
// melts back into 8 grains of molten metal if they fit here
|
||||
let fits = true;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ function checkLedger() {
|
||||
const mark = id => { if (!ledger[id]) { ledger[id] = tick || 1; emit({ t: 'milestone', id }); } };
|
||||
if (stats.dug >= 15) mark('dig');
|
||||
if (seen[FIRE]) { mark('fire'); if (!player.lens) { player.lens = true; } }
|
||||
if (seen[BRICK] || seen[RBRICK]) mark('brick');
|
||||
if (seen[BRICK] || seen[RBRICK] || seen[BARBR]) mark('brick');
|
||||
if (seen[CHARCOAL]) mark('charcoal');
|
||||
if (stats.grown > 0) mark('grow');
|
||||
if (seen[MCU]) mark('copper');
|
||||
|
||||
@@ -11,8 +11,8 @@ const EMPTY = 0, GRASS = 1, DIRT = 2, LDIRT = 3, SAND = 4, GRAVEL = 5, CLAY = 6,
|
||||
ZNV = 63, ZNORE = 64, ZINC = 65, MZN = 66, SCRZN = 67, BARZN = 68,
|
||||
AGV = 69, AGORE = 70, SILVER = 71, MAG = 72, SCRAG = 73, BARAG = 74,
|
||||
AUV = 75, AUORE = 76, GOLD = 77, MAU = 78, SCRAU = 79, BARAU = 80,
|
||||
BRONZE = 81, MBZ = 82, SCRBZ = 83, BARBZ = 84, BRASS = 85, MBS = 86, SCRBS = 87, BARBS = 88, DOCKW = 89, MSLAG = 90, PIPE = 91, BARGL = 92, CUTST = 93, BARSB = 94, GRINDER = 95, SAWB = 96, PLANK = 97;
|
||||
const NMAT = 98;
|
||||
BRONZE = 81, MBZ = 82, SCRBZ = 83, BARBZ = 84, BRASS = 85, MBS = 86, SCRBS = 87, BARBS = 88, DOCKW = 89, MSLAG = 90, PIPE = 91, BARGL = 92, CUTST = 93, BARSB = 94, GRINDER = 95, SAWB = 96, PLANK = 97, PRESSB = 98, GREENB = 99, BARBR = 100;
|
||||
const NMAT = 101;
|
||||
|
||||
const MD = [];
|
||||
function def(id, o) {
|
||||
@@ -64,6 +64,7 @@ def(SHAFT, { name: 'Shaft', col: [150, 110, 64], v: 6, k: 0.005, hard: 2, ign: 3
|
||||
def(GATE, { name: 'Gate', col: [146, 74, 58], v: 6, k: 0.004, hard: 3, melt: 1750, meltTo: MAGMA, partMat: true });
|
||||
def(GRINDER, { name: 'Grinder', col: [64, 70, 80], v: 4, k: 0.035, hard: 6, melt: 1450, meltTo: MST, partMat: true });
|
||||
def(SAWB, { name: 'Saw', col: [74, 80, 90], v: 4, k: 0.035, hard: 6, melt: 1450, meltTo: MST, partMat: true });
|
||||
def(PRESSB, { name: 'Brick press', col: [74, 80, 90], v: 4, k: 0.035, hard: 6, melt: 1450, meltTo: MST, partMat: true });
|
||||
def(SPRING, { name: 'Spring', col: [92, 112, 128], v: 30, k: 0.012, hard: 9, yld: 0, desc: 'Groundwater seeps out of this rock whenever there is room next to it.' });
|
||||
def(RSTONE, { name: 'Stone rubble', ph: PH_POWDER, col: [126, 125, 130], v: 30, dens: 1.8, k: 0.01, hard: 0, melt: 1250, meltTo: MAGMA, bag: true, desc: 'Broken stone. 16 grains make a stone block.' });
|
||||
def(RGRAN, { name: 'Granite rubble', ph: PH_POWDER, col: [164, 128, 124], v: 32, dens: 1.9, k: 0.01, hard: 0, melt: 1260, meltTo: MAGMA, bag: true, desc: 'Broken granite. Makes granite blocks.' });
|
||||
@@ -106,6 +107,10 @@ metalFamily({ solid: BRASS, molten: MBS, scrap: SCRBS, bar: BARBS, name: 'Brass'
|
||||
desc: 'Copper with zinc melted in. Golden and valuable.' });
|
||||
def(BARGL, { name: 'Glass brick', ph: PH_ITEM, col: [176, 218, 228], v: 0, dens: 2.5, k: 0, hard: 0, melt: 1300, meltTo: MGL, bag: true, desc: 'Cast from molten glass in an Ingot mold: 8 grains of glass. Sells well, and 2 make a glass wall block.' });
|
||||
def(PLANK, { name: 'Plank', ph: PH_ITEM, col: [204, 158, 104], v: 0, dens: 0.6, k: 0, hard: 0, melt: 9999, bag: true, desc: 'Sawn from 8 wood chunks by a Saw. Builders buy them, and 2 make a wood wall block.' });
|
||||
def(GREENB, { name: 'Green brick', ph: PH_ITEM, col: [202, 164, 136], v: 0, dens: 1.8, k: 0, hard: 0, melt: 1750, meltTo: MAGMA, bag: true, desc: 'Unfired clay pressed into shape by a Brick press. Fire it above ~900°C to make a Brick.' });
|
||||
def(BARBR, { name: 'Brick', ph: PH_ITEM, col: [174, 76, 56], v: 0, dens: 1.8, k: 0, hard: 0, melt: 1750, meltTo: MAGMA, bag: true, desc: 'Fired clay brick. Builders buy them, and 2 make a brick wall block.' });
|
||||
// An item that fires into another item when hot.
|
||||
const FIRETO = new Uint8Array(NMAT); FIRETO[GREENB] = BARBR;
|
||||
def(CUTST, { name: 'Cut stone', col: [168, 162, 150], v: 6, k: 0.012, hard: 4, melt: 1450, meltTo: MAGMA, yld: BARSB, desc: 'Dressed stone blocks laid in courses. Neater than rough stone, and it stands 200°C more heat before it slumps.' });
|
||||
def(BARSB, { name: 'Stone block', ph: PH_ITEM, col: [172, 166, 154], v: 0, dens: 2.6, k: 0, hard: 0, melt: 1450, meltTo: MAGMA, bag: true, desc: 'A block of stone cut square by a Saw, from 8 grains of rubble. Builders buy them, and 2 make a cut stone wall block.' });
|
||||
def(PIPE, { name: 'Pipe', col: [176, 112, 72], v: 4, k: 0.04, cap: 1.5, hard: 4, melt: 1085, meltTo: MCU, partMat: true });
|
||||
|
||||
+5
-3
@@ -4,7 +4,7 @@
|
||||
// Everything you build snaps to a grid of 4x4-grain blocks. The world itself
|
||||
// stays grain-level; only built pieces snap.
|
||||
const BS = 4;
|
||||
const BP_WALL = 1, BP_BELT = 2, BP_TUBE = 3, BP_SHAFT = 4, BP_GRATE = 5, BP_GATE = 6, BP_FILTER = 7, BP_PIPE = 8, BP_PUMP = 9, BP_OUTLET = 10, BP_GRIND = 11, BP_SAW = 12;
|
||||
const BP_WALL = 1, BP_BELT = 2, BP_TUBE = 3, BP_SHAFT = 4, BP_GRATE = 5, BP_GATE = 6, BP_FILTER = 7, BP_PIPE = 8, BP_PUMP = 9, BP_OUTLET = 10, BP_GRIND = 11, BP_SAW = 12, BP_PRESS = 13;
|
||||
function isPipeCode(c) { return c === BP_PIPE || c === BP_PUMP || c === BP_OUTLET; }
|
||||
// Filters: each filter block has a set of materials and a mode. In drop mode (inv 0)
|
||||
// the chosen materials fall through and everything else rides along on top; in carry
|
||||
@@ -25,8 +25,8 @@ function sameFilter(a, b) { return a.inv === b.inv && a.m.length === b.m.length
|
||||
const WALL_OF = new Uint8Array(NMAT);
|
||||
WALL_OF[LDIRT] = DIRT; WALL_OF[RSTONE] = STONE; WALL_OF[RGRAN] = GRANITE; WALL_OF[RBAS] = BASALT; WALL_OF[LCLAY] = CLAY;
|
||||
WALL_OF[LWOOD] = WOOD; WALL_OF[RBRICK] = BRICK; WALL_OF[CULLET] = GLASS; WALL_OF[BARCU] = COPPER; WALL_OF[BARFE] = IRON; WALL_OF[BARST] = STEEL;
|
||||
WALL_OF[BARSB] = CUTST; WALL_OF[PLANK] = WOOD; WALL_OF[BARGL] = GLASS;
|
||||
const WALL_LIST = [RSTONE, BARSB, PLANK, LCLAY, RBRICK, LDIRT, LWOOD, CULLET, BARGL, RGRAN, RBAS, BARCU, BARFE, BARST];
|
||||
WALL_OF[BARSB] = CUTST; WALL_OF[PLANK] = WOOD; WALL_OF[BARBR] = BRICK; WALL_OF[BARGL] = GLASS;
|
||||
const WALL_LIST = [RSTONE, BARSB, PLANK, BARBR, LCLAY, RBRICK, LDIRT, LWOOD, CULLET, BARGL, RGRAN, RBAS, BARCU, BARFE, BARST];
|
||||
const BAR_OF = new Uint8Array(NMAT); BAR_OF[COPPER] = BARCU; BAR_OF[IRON] = BARFE; BAR_OF[STEEL] = BARST;
|
||||
BAR_OF[GLASS] = BARGL; BAR_OF[CUTST] = BARSB; BAR_OF[WOOD] = PLANK; BAR_OF[TIN] = BARSN; BAR_OF[ZINC] = BARZN; BAR_OF[SILVER] = BARAG; BAR_OF[GOLD] = BARAU; BAR_OF[BRONZE] = BARBZ; BAR_OF[BRASS] = BARBS;
|
||||
const GRAINS_PER_BAR = 8;
|
||||
@@ -59,6 +59,8 @@ const PIECES = [
|
||||
desc: 'Lets a pipe line\'s liquid out of the side its arrow points to, wherever there is room for it. Press F to open or close it.' },
|
||||
{ id: 'grinder', code: BP_GRIND, name: 'Grinder', kind: 'block', cost: [[CASH, 60]],
|
||||
desc: 'Grinds rubble, gravel, sand and dirt resting on top into sand and the odd grain of ore. Results drop out below; keep that space clear. Wider rows grind faster. Stack under a Saw to cut stone and grind the rest.' },
|
||||
{ id: 'press', code: BP_PRESS, name: 'Brick press', kind: 'block', cost: [[CASH, 60]],
|
||||
desc: 'Presses clay lumps resting on top into a green brick for every 8. They drop out underneath; put a belt or an open drop under it. Fire green bricks in a fire hotter than about 900°C to make Bricks. Wider rows press faster.' },
|
||||
{ id: 'saw', code: BP_SAW, name: 'Saw', kind: 'block', cost: [[CASH, 90]],
|
||||
desc: 'Cuts stone rubble into stone blocks and wood chunks into planks, one from every 8 grains resting on top. They drop out underneath and pile up there: put a belt or an open drop under it to carry them away. Wider rows cut faster. Stack over a Grinder to grind everything else.' },
|
||||
{ id: 'wheel', name: 'Water wheel', kind: 'machine', bw: 3, bh: 3, cost: [[LWOOD, 48]], hidden: POWER_FREE,
|
||||
|
||||
+12
-7
@@ -15,12 +15,12 @@ const CUT_PER_BRICK = 8;
|
||||
const SAW_CUTS = []; SAW_CUTS[RSTONE] = BARSB; SAW_CUTS[LWOOD] = PLANK;
|
||||
// Block hoppers share an outlet down a vertical stack; only its top spends work.
|
||||
let procState = new Map(), procBlocks = [], procDirty = true;
|
||||
function isProcCode(c) { return c === BP_GRIND || c === BP_SAW; }
|
||||
function isProcCode(c) { return c === BP_GRIND || c === BP_SAW || c === BP_PRESS; }
|
||||
function rebuildProcessors() {
|
||||
procBlocks = [];
|
||||
for (let b = 0; b < NB; b++) if (isProcCode(blockP[b])) {
|
||||
procBlocks.push(b);
|
||||
if (!procState.has(b)) procState.set(b, { work: 0, cut: { [RSTONE]: 0, [LWOOD]: 0 }, busyT: -999, blocked: false });
|
||||
if (!procState.has(b)) procState.set(b, { work: 0, press: 0, cut: { [RSTONE]: 0, [LWOOD]: 0 }, busyT: -999, blocked: false });
|
||||
}
|
||||
procDirty = false;
|
||||
}
|
||||
@@ -45,15 +45,19 @@ function procFeed(b, m, T) {
|
||||
} else if (blockP[b] === BP_SAW && SAW_CUTS[m]) {
|
||||
if (++s.cut[m] < CUT_PER_BRICK) return;
|
||||
s.cut[m] = 0; m = SAW_CUTS[m];
|
||||
} else if (blockP[b] === BP_PRESS && m === LCLAY) {
|
||||
if (++s.press < CUT_PER_BRICK) return;
|
||||
s.press = 0; m = GREENB;
|
||||
}
|
||||
if (b === end) break;
|
||||
b += BW;
|
||||
}
|
||||
if (m === BARSB || m === PLANK) {
|
||||
if (m === BARSB || m === PLANK || m === GREENB) {
|
||||
const e = spawnBar(m, x, (((end / BW) | 0) + 1) * BS, (rnd() - 0.5) * 0.1, 0.05);
|
||||
if (e) {
|
||||
e.T = T; discover(m, x, y, m === PLANK ? LWOOD : RSTONE, 'cut');
|
||||
if (m === PLANK) stats.planks = (stats.planks || 0) + 1;
|
||||
e.T = T; discover(m, x, y, m === GREENB ? LCLAY : m === PLANK ? LWOOD : RSTONE, m === GREENB ? 'press' : 'cut');
|
||||
if (m === GREENB) stats.pressed = (stats.pressed || 0) + 1;
|
||||
else if (m === PLANK) stats.planks = (stats.planks || 0) + 1;
|
||||
else stats.bricks = (stats.bricks || 0) + 1;
|
||||
}
|
||||
} else setCell(procSlot(end), m, T, 0);
|
||||
@@ -71,9 +75,10 @@ function procBlocksTick() {
|
||||
const i = y * W + x + ((k + tick) & 3), m = mat[i];
|
||||
if (m === EMPTY || PH[m] === PH_GAS || PH[m] === PH_SOLID || stamp[i] === tickStamp) continue;
|
||||
let brick = false;
|
||||
if (SAW_CUTS[m]) for (let q = b; q <= end; q += BW) {
|
||||
if (SAW_CUTS[m] || m === LCLAY) for (let q = b; q <= end; q += BW) {
|
||||
if (blockP[q] === BP_GRIND && REFINE[m]) break;
|
||||
if (blockP[q] === BP_SAW) { brick = procState.get(q).cut[m] + 1 >= CUT_PER_BRICK; break; }
|
||||
if (blockP[q] === BP_PRESS && m === LCLAY) { brick = procState.get(q).press + 1 >= CUT_PER_BRICK; break; }
|
||||
if (blockP[q] === BP_SAW && SAW_CUTS[m]) { brick = procState.get(q).cut[m] + 1 >= CUT_PER_BRICK; break; }
|
||||
}
|
||||
if (procSlot(end) < 0 || brick && !entFreeAt(x, (((end / BW) | 0) + 1) * BS)) {
|
||||
for (let q = b; q <= end; q += BW) procState.get(q).blocked = true;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ const STARTER_DESIGNS = [
|
||||
const MILESTONES = [
|
||||
{ id: 'dig', title: 'Break ground', msg: 'Broken material falls loose. The Pneumatic nozzle (2) picks up and blows the selection. Click or Q/E in the bag selects; Ctrl+click mixes. Hold Ctrl to see everything found. Clear returns to picking what you click. Shift: everything.', hint: 'Hold the left mouse button with the Drill (1): it sends pulses at the cursor that shake rock until it shatters. It falls as rubble, ore and coal.' },
|
||||
{ id: 'fire', title: 'First fire', hint: 'Pick up coal or wood chunks with the nozzle, blow a pile out with right click, then hold the Igniter (4) on it. Fuel only burns where it touches open air.', reward: 'Thermal lens unlocked. Press H to see heat.' },
|
||||
{ id: 'brick', title: 'Fired brick', hint: 'Clay turns into brick after a while above about 900°C, hotter than an open wood fire gets. Blow clay lumps into a coal fire, best walled in like a furnace, and pick up the brick rubble with the Pneumatic nozzle. Brick rubble builds brick blocks.', reward: 'Brick insulates far better than stone and survives 1750°C.' },
|
||||
{ id: 'brick', title: 'Fired brick', hint: 'Clay turns into brick after a while above about 900°C, hotter than an open wood fire gets. Blow clay lumps into a coal fire, best walled in like a furnace, and pick up the brick rubble with the Pneumatic nozzle. Brick rubble builds brick blocks. A Brick press makes neat green bricks to fire.', reward: 'Brick insulates far better than stone and survives 1750°C.' },
|
||||
{ id: 'charcoal', title: 'Charcoal', hint: 'Wood that gets hot without air turns into charcoal instead of burning. Bury a burning pile of wood chunks under dirt, or heat a sealed box of wood chunks from outside.', reward: 'A fuel you can grow: nearly as hot as coal.' },
|
||||
{ id: 'grow', title: 'Plant a tree', msg: 'Wood is renewable. Plant rows of acorns on dirt to farm it.', hint: 'Cutting down a tree drops acorns. Leave one on dirt or grass under open sky and it sprouts, then grows into a tree in about a minute and a half.' },
|
||||
{ id: 'copper', title: 'Molten copper', msg: 'Molten copper sinks to the bottom of the charge. Get it into a mold before it sets.', hint: 'Copper ore melts at 1085°C. An open fire loses too much heat, so wall coal and ore in with blocks and leave a small vent at the top for smoke. Mix ore and coal about half and half: Ctrl+click coal and copper ore in the bag to blow a mix. Right click blows an even mix.' },
|
||||
|
||||
@@ -4,7 +4,7 @@ const BUILD_CATS = [
|
||||
['Structure', ['wall', 'grate', 'gate']],
|
||||
['Moving', ['belt', 'filter', 'tube']],
|
||||
['Liquids', ['pipe', 'pump', 'outlet']],
|
||||
['Machines', ['fan', 'grinder', 'saw', 'silo']],
|
||||
['Machines', ['fan', 'grinder', 'saw', 'press', 'silo']],
|
||||
['Molds', ['ingotmold', 'bitmold', 'tankmold']],
|
||||
];
|
||||
const BUILD_ORDER = BUILD_CATS.flatMap(c => c[1]);
|
||||
@@ -20,6 +20,7 @@ const PIECE_ICONS = {
|
||||
outlet: '<path d="M2 7h12a4 4 0 0 1 4 4v3"/><path d="M2 11h10a2 2 0 0 1 2 2v1"/><path d="M15 18v1.5M18 20v1.5M12 20v1.5"/>',
|
||||
fan: '<circle cx="12" cy="12" r="1.8"/><path d="M12 10.2c-.4-3.6 1.8-6 4-4.8 2 1.2.4 3.8-4 4.8zM13.8 12c3.6-.4 6 1.8 4.8 4-1.2 2-3.8.4-4.8-4zM12 13.8c.4 3.6-1.8 6-4 4.8-2-1.2-.4-3.8 4-4.8zM10.2 12c-3.6.4-6-1.8-4.8-4 1.2-2 3.8-.4 4.8 4z"/>',
|
||||
grinder: '<path d="M3 4h18l-5 7H8z"/><circle cx="9" cy="15.5" r="2.8"/><circle cx="15" cy="15.5" r="2.8"/><path d="M12 20v2"/>',
|
||||
press: '<path d="M5 3h14l-3 5H8zM12 8v5M5 13h14v3H5z"/><rect x="8" y="18" width="8" height="3"/>',
|
||||
saw: '<path d="M5 3h14l-3 5H8z"/><circle cx="12" cy="15" r="5"/><circle cx="12" cy="15" r="1.2"/><path d="M12 9.2v1.6M17.8 15h-1.6M12 20.8v-1.6M6.2 15h1.6"/>',
|
||||
silo: '<path d="M6 5.5h12v11H6z"/><path d="M6 5.5l1-2h10l1 2M6 16.5l4 3h4l4-3M7 16.5v5M17 16.5v5"/><path d="M15.5 8v6"/>',
|
||||
ingotmold: '<path d="M3 9h18l-2 7H5z"/><path d="M9.2 9l.8 7M14.8 9l-.8 7"/>',
|
||||
|
||||
+4
-3
@@ -32,6 +32,7 @@ function howText(e) {
|
||||
case 'alloy': return `${F} melted into molten copper and the two mixed.`;
|
||||
case 'char': return `${F} got hot with no air to burn in, and charred.`;
|
||||
case 'refine': return `Ground out of ${f}.`;
|
||||
case 'press': return `Pressed from ${f} by a Brick press.`;
|
||||
case 'cut': return `Cut from ${f} by a saw.`;
|
||||
default: return '';
|
||||
}
|
||||
@@ -92,9 +93,9 @@ function hoverInfo(ax, ay) {
|
||||
if (mm.type === 'fan') { t2.push(mm.on ? 'on' : 'off · press F'); if (mm.hot > 760) { t2.push(`${mm.hot}°C · melts at 1085°C`); warn = 'too hot'; } }
|
||||
if (mm.type === 'silo') t2.push(mm.sn ? `holds ${mm.sn.toLocaleString('en-US')} / ${SILO_CAP.toLocaleString('en-US')} ${MD[mm.sm].name.toLowerCase()}` : `empty (holds ${SILO_CAP.toLocaleString('en-US')} grains of one material)`, mm.open ? 'gate open · F shuts it' : 'gate shut · F opens it');
|
||||
} else if (isProcCode(b)) {
|
||||
const s = procState.get((ay >> 2) * BW + (ax >> 2)), saw = b === BP_SAW;
|
||||
t1 = saw ? 'Saw' : 'Grinder';
|
||||
t2.push(s && s.blocked ? saw ? 'stopped: no room underneath; a belt there carries them away' : 'stopped: clear the space under it' : s && tick - s.busyT < 30 ? saw ? 'cutting' : 'grinding' : saw ? 'idle: drop stone rubble or wood chunks on top' : 'idle: drop rubble, gravel, sand or dirt on top', saw ? `${(stats.bricks || 0).toLocaleString('en-US')} stone blocks, ${(stats.planks || 0).toLocaleString('en-US')} planks cut` : `${(stats.refined || 0).toLocaleString('en-US')} ground, ${(stats.refinedOre || 0).toLocaleString('en-US')} ore found`);
|
||||
const s = procState.get((ay >> 2) * BW + (ax >> 2)), saw = b === BP_SAW, press = b === BP_PRESS;
|
||||
t1 = press ? 'Brick press' : saw ? 'Saw' : 'Grinder';
|
||||
t2.push(s && s.blocked ? saw || press ? 'stopped: no room underneath; a belt there carries them away' : 'stopped: clear the space under it' : s && tick - s.busyT < 30 ? press ? 'pressing' : saw ? 'cutting' : 'grinding' : press ? 'idle: drop clay lumps on top' : saw ? 'idle: drop stone rubble or wood chunks on top' : 'idle: drop rubble, gravel, sand or dirt on top', press ? `${stats.pressed || 0} green bricks pressed` : saw ? `${(stats.bricks || 0).toLocaleString('en-US')} stone blocks, ${(stats.planks || 0).toLocaleString('en-US')} planks cut` : `${(stats.refined || 0).toLocaleString('en-US')} ground, ${(stats.refinedOre || 0).toLocaleString('en-US')} ore found`);
|
||||
} else if (p === P_FILTER) {
|
||||
const fb = ((ay / BS) | 0) * BW + ((ax / BS) | 0), pr = filterParts(filterInfo(fb)), ar = blockV[fb] & 128 ? '→' : '←';
|
||||
t1 = 'Filter ' + ar; t2.push(`drops ${pr.drops}`, `carries ${pr.rides} ${ar}`, 'F to change · I shows all');
|
||||
|
||||
+3
-3
@@ -27,7 +27,7 @@ function renderNotebook() {
|
||||
renderMarketTab(body);
|
||||
} else if (nbTab === 'Materials') {
|
||||
let rows = '', unknown = 0;
|
||||
const list = [DIRT, LDIRT, STONE, RSTONE, BARSB, PLANK, CLAY, LCLAY, WOOD, LWOOD, ACORN, CHARCOAL, SNOW, ICE, COALV, COAL, CUV, CUORE, FEV, FEORE, SAND, GRAVEL, GRANITE, RGRAN, BASALT, RBAS,
|
||||
const list = [DIRT, LDIRT, STONE, RSTONE, BARSB, PLANK, GREENB, BARBR, CLAY, LCLAY, WOOD, LWOOD, ACORN, CHARCOAL, SNOW, ICE, COALV, COAL, CUV, CUORE, FEV, FEORE, SAND, GRAVEL, GRANITE, RGRAN, BASALT, RBAS,
|
||||
BRICK, RBRICK, GLASS, CULLET, COPPER, SCRCU, BARCU, IRON, SCRFE, BARFE, STEEL, SCRST, BARST, ASH, SLAG, MSLAG, WATER, STEAM, MAGMA, MCU, MFE, MST, MGL, FIRE, SMOKE, SNV, SNORE, TIN, MSN, SCRSN, BARSN, ZNV, ZNORE, ZINC, MZN, SCRZN, BARZN, AGV, AGORE, SILVER, MAG, SCRAG, BARAG, AUV, AUORE, GOLD, MAU, SCRAU, BARAU, BRONZE, MBZ, SCRBZ, BARBZ, BRASS, MBS, SCRBS, BARBS];
|
||||
for (const m of list) {
|
||||
if (!seen[m]) { unknown++; continue; }
|
||||
@@ -58,7 +58,7 @@ function orderName(o) { return `${o.who ? o.who + ': ' : ''}${o.qty.toLocaleStri
|
||||
function orderLeft(o) { return Math.max(0, o.due - tick); }
|
||||
const MARKET_GROUPS = [
|
||||
['Raw', [COAL, LWOOD, ACORN, SAND, LCLAY, RGRAN, RBAS, CUORE, FEORE, SNORE, ZNORE]],
|
||||
['Bulk (builders)', [RSTONE, GRAVEL, BARSB, PLANK]],
|
||||
['Bulk (builders)', [RSTONE, GRAVEL, BARSB, PLANK, GREENB, BARBR]],
|
||||
['Refined', [CHARCOAL, RBRICK, CULLET, BARGL, SCRCU, SCRFE, SCRST, SCRSN, SCRZN, BARCU, BARSN, BARZN, BARFE, BARST]],
|
||||
['Alloys', [SCRBZ, SCRBS, BARBZ, BARBS]],
|
||||
['Precious', [AGORE, AUORE, SCRAG, SCRAU, BARAG, BARAU]],
|
||||
@@ -182,7 +182,7 @@ function controlsHtml() {
|
||||
const tools = [
|
||||
['1 Resonance drill', 'Hold left click to send pulses from the bot toward the cursor: rock they shake hard enough shatters and falls as rubble, ore, coal or scrap, and trees come apart into wood chunks and acorns. Q and E set the pulse width: narrow bores a tunnel fast, wide clears a big cone slowly, medium is in between. R over a material tunes the drill to it, so only that shatters (great for pulling a vein out of the rock); R again untunes. Built blocks are never harmed. Better bits dig harder rock, faster and further.'],
|
||||
['2 Pneumatic nozzle', "Left drag picks up the selection, or what you click if nothing is selected. Right click blows the selection. Click a bag name or Q/E selects one; Ctrl+click mixes. Hold Ctrl to see everything found. Clear removes the selection. Bars blow alone. Blowing out the last of a material deselects it. Shift while not flying takes everything; Shift + right click blows everything loose in the bag."],
|
||||
['3 Build', 'Places pieces on a grid of 4×4 blocks: wall blocks, belts, tubes, filters, grates, gates, pipes, pumps, outlets, Grinders and Saws, machines (fans and silos) and molds. Drag for a line, hold Shift while dragging for a filled rectangle. Right click takes a piece back. Your bot flies through anything you build.'],
|
||||
['3 Build', 'Places pieces on a grid of 4×4 blocks: wall blocks, belts, tubes, filters, grates, gates, pipes, pumps, outlets, Grinders, Saws and Brick presses, machines (fans and silos) and molds. Drag for a line, hold Shift while dragging for a filled rectangle. Right click takes a piece back. Your bot flies through anything you build.'],
|
||||
['4 Igniter', 'Heats a small spot to 640°C, and its flame reaches a few grains into a pile. Enough to light coal and wood that touch air.'],
|
||||
['Copy, cut and paste', 'Hold C (copy) or X (cut) and drag a box over what you built; let go and it is picked up, ready to paste. Cut takes it down and refunds it to your bag. Click to place ghosts: your bot builds them from your bag when it is close. R flips, V pastes again, right click or Esc stops. Ctrl+Z undoes building. The notebook (B) keeps saved blueprints and a few starter designs.'],
|
||||
];
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ const ICONS = {
|
||||
ignite: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"><path d="M12 21c-4 0-6-2.6-6-5.6 0-3.4 3-5 3.6-8.4C12.5 9 14 11 14 13c1-.6 1.6-1.8 1.6-3 2 1.6 2.4 3.6 2.4 5.4 0 3-2 5.6-6 5.6z"/></svg>',
|
||||
blueprint: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="11" height="11" rx="1" stroke-dasharray="2.5 2"/><rect x="10" y="10" width="11" height="11" rx="1"/></svg>',
|
||||
};
|
||||
const BAG_ORDER = [BARAU, BARAG, BARBZ, BARBS, BARST, BARFE, BARCU, BARSN, BARZN, BARGL, BARSB, PLANK, AUORE, AGORE, ZNORE, SNORE, RSTONE, LCLAY, RBRICK, LDIRT, LWOOD, ACORN, COAL, CHARCOAL, CUORE, FEORE, SAND, GRAVEL, RGRAN, RBAS, CULLET,
|
||||
const BAG_ORDER = [BARAU, BARAG, BARBZ, BARBS, BARST, BARFE, BARCU, BARSN, BARZN, BARGL, BARSB, PLANK, GREENB, BARBR, AUORE, AGORE, ZNORE, SNORE, RSTONE, LCLAY, RBRICK, LDIRT, LWOOD, ACORN, COAL, CHARCOAL, CUORE, FEORE, SAND, GRAVEL, RGRAN, RBAS, CULLET,
|
||||
SCRCU, SCRFE, SCRST, SCRSN, SCRZN, SCRAG, SCRAU, SCRBZ, SCRBS, ASH, SLAG, SNOW, WATER, MAGMA, MCU, MFE, MST, MGL, MSN, MZN, MAG, MAU, MBZ, MBS];
|
||||
const GAME = {
|
||||
ctrl: false,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
id: t28
|
||||
title: Brick press for clay bricks
|
||||
report: |
|
||||
(agent) The Brick press ($60) is in the Machines tab next to the Saw. Every 8 clay lumps resting
|
||||
on it become a Green brick that drops out underneath. Drop green bricks into a fire hotter than
|
||||
about 900°C (blow them in, belt them in, or put the press over a fire) and they turn into Bricks.
|
||||
2 Bricks build a brick wall block, they sell for about $9, and builders order them. Please try
|
||||
pressing and firing a batch, and check that the press's moving plate reads well.
|
||||
status: Review
|
||||
created: 2026-10-24
|
||||
updated: 2026-10-24T20:55:54Z
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
- Clay bricks should be made the same way as the Saw's stone blocks: a 1-block hopper piece takes grains on top and drops an item below. A Brick press squeezes clay lumps into green bricks, and like real bricks they then have to be fired to become Bricks.
|
||||
|
||||
## Subtasks
|
||||
|
||||
- [x] Brick press block: every 8 clay lumps resting on it make a Green brick that drops out underneath
|
||||
- [x] A Green brick that gets hotter than about 900°C fires into a Brick
|
||||
- [x] Bricks build brick wall blocks (2 per block) and sell; builders order them
|
||||
@@ -3,7 +3,7 @@ id: t4
|
||||
title: Hopper blocks instead of fixed-size hoppers
|
||||
status: Review
|
||||
created: 2026-10-24
|
||||
updated: 2026-10-24T20:06:51Z
|
||||
updated: 2026-10-24T20:55:54Z
|
||||
tags: [discussion]
|
||||
order: 1
|
||||
report: |
|
||||
@@ -14,6 +14,10 @@ report: |
|
||||
else. If the space underneath fills up the block stops; hover it to see why. The Refiner and
|
||||
Stone cutter are gone from the menu; ones already built keep working. Please try a wide grinder
|
||||
hopper fed with the nozzle, a Saw on a Grinder, and an old save that has a Refiner.
|
||||
Follow-ups: the old Refiner and Stone cutter code is removed (a save that still has one loads
|
||||
and refunds it). Grinders now look like a pair of grinding wheels and Saws like a round blade.
|
||||
The Saw also cuts wood chunks into Planks, and its stone output is now called a Stone block.
|
||||
Clay bricks moved to their own task, t28 (Brick press).
|
||||
---
|
||||
|
||||
## Context
|
||||
@@ -24,3 +28,8 @@ report: |
|
||||
|
||||
- [x] Grinder block (does what the Refiner does) and Saw block (Stone cutter), 1 block each; side by side they make a wider, faster hopper
|
||||
- [x] Refiner and Stone cutter leave the build menu; built ones in old saves keep working
|
||||
- [x] Remove the Refiner and Stone cutter code; an old save that still has one loads with the machine taken out and its cost refunded
|
||||
- [x] Grinders look like two grinding wheels and Saws like a round blade, turning while they work
|
||||
- [x] The Saw also cuts wood chunks into Planks, which build wood walls and sell
|
||||
- [x] Rename the Saw's "Stone brick" to "Stone block", so only fired clay is called a brick
|
||||
- [x] The Saw's description and "stopped" hover say to put a belt or an open drop under it
|
||||
|
||||
+1
-1
@@ -691,7 +691,7 @@ with sync_playwright() as p:
|
||||
check('and Ctrl+Z swaps the belt back', ev(f'blockP[({bby} + 1) * BW + {bbx} - 4]') == ev('BP_BELT') and not ev(f"machines.some(m => m && m.type === 'fan' && m.x === ({bbx} - 4) * 4)"), ev('GAME.status'))
|
||||
|
||||
# 7a. hopper blocks: the Machines tab has Grinder and Saw instead of the Refiner and Stone cutter; drag a row
|
||||
check('the Machines tab has Grinder and Saw but not the Refiner or Stone cutter', ev("(() => { const ids = BUILD_CATS.find(c => c[0] === 'Machines')[1]; return ids.includes('grinder') && ids.includes('saw') && !ids.includes('refiner') && !ids.includes('cutter'); })()"))
|
||||
check('the Machines tab has Grinder and Saw but not the Refiner or Stone cutter', ev("(() => { const ids = BUILD_CATS.find(c => c[0] === 'Machines')[1]; return ids.includes('grinder') && ids.includes('saw') && ids.includes('press') && !ids.includes('refiner') && !ids.includes('cutter'); })()"))
|
||||
ev('money = 1000')
|
||||
ok = select('3', "piece().id === 'grinder'")
|
||||
ev(f"for (let y = {(bby+3)*4}; y < {(bby+4)*4}; y++) for (let x = {(bbx-8)*4}; x < {(bbx+4)*4}; x++) if (!blockP[((y/4)|0)*BW + ((x/4)|0)]) setCell(y*W+x, EMPTY, 20, 0);")
|
||||
|
||||
+16
-1
@@ -74,6 +74,21 @@ function feedHopper(m, n, bottom = 76, clearItems = true) {
|
||||
for (let t = 0; t < 4; t++) { tick++; tickStamp++; procBlocksTick(); }
|
||||
}`);
|
||||
}
|
||||
hopper('BP_PRESS'); run('stats.pressed = 0;'); feedHopper('LCLAY', 8);
|
||||
check('a Brick press makes one green brick from eight clay lumps', run('stats.pressed === 1 && ents.length === 1 && ents[0].m === GREENB && ents[0].iy === 76 && seen[GREENB]'));
|
||||
feedHopper('CUORE', 1);
|
||||
check('a Brick press passes other grains through', run('mat[76*W+81] === CUORE && temp[76*W+81] === 60'));
|
||||
check('two fired bricks build a brick wall block', run('WALL_OF[BARBR] === BRICK') && JSON.stringify(run('wallCost(BARBR, 16)')) === JSON.stringify([[run('BARBR'), 2]]));
|
||||
hopper('BP_PRESS'); run('stats.pressed = 0;'); feedHopper('LCLAY', 7);
|
||||
run('setCell(77*W+80, STONE, 20, 0); setCell(71*W+80, LCLAY, 20, 0); stamp[71*W+80] = 0; for (let k = 0; k < 8; k++) { tick++; tickStamp++; procBlocksTick(); }');
|
||||
check('a press waits until a whole brick fits underneath', run('mat[71*W+80] === LCLAY && procState.get(18*BW+20).press === 7 && procState.get(18*BW+20).blocked && stats.pressed === 0'));
|
||||
hopper('BP_PRESS', true); feedHopper('LCLAY', 8, 80);
|
||||
check('a green brick drops below a press and Grinder stack', run('ents.length === 1 && ents[0].m === GREENB && ents[0].iy === 80'));
|
||||
for (const heat of [1000, 500]) {
|
||||
flatWorld(run, 240, 160, 100);
|
||||
run(`spawnBar(GREENB, 80, 98, 0, 0, ${heat}); for (let k = 0; k < 2000; k++) { temp.fill(${heat}); simTick(); }`);
|
||||
check(`a green brick at ${heat}°C ${heat === 1000 ? 'fires' : 'stays unfired'}`, run(`ents.length === 1 && ents[0].m === ${heat === 1000 ? 'BARBR' : 'GREENB'} && occ[ents[0].iy*W+ents[0].ix] === 1`));
|
||||
}
|
||||
hopper('BP_SAW'); feedHopper('RSTONE', 8);
|
||||
check('a Saw cuts eight stone grains into one stone block below', run('stats.bricks === 1 && ents[0].iy === 76'));
|
||||
hopper('BP_SAW'); feedHopper('LWOOD', 8);
|
||||
@@ -131,7 +146,7 @@ for (const [type, refund] of [['refiner', 120], ['cutter', 90], ['unknown', 0]])
|
||||
|
||||
// ---- builders' orders: bulk rubble, gravel and stone blocks at a few times a tiny price
|
||||
flatWorld(run, 240, 160, 100);
|
||||
run('seen[PLANK] = 0; seen[RSTONE] = 1; seen[GRAVEL] = 1; seen[BARSB] = 1; orders = []; ordersDone = 0;');
|
||||
run('seen[BARBR] = 0; seen[PLANK] = 0; seen[RSTONE] = 1; seen[GRAVEL] = 1; seen[BARSB] = 1; orders = []; ordersDone = 0;');
|
||||
const os = JSON.parse(run('JSON.stringify(Array.from({ length: 40 }, () => makeBuildersOrder()))'));
|
||||
const okOrders = os.every(o => o && o.who === 'Builders' && [run('RSTONE'), run('GRAVEL'), run('SAND'), run('BARSB')].includes(o.m) && o.pay > 0 && o.pay < 400);
|
||||
check("builders post orders for rubble, gravel and stone blocks that pay a little", okOrders, os.slice(0, 4).map(o => `${o.qty} of ${o.m} for $${o.pay}`).join(', '));
|
||||
|
||||
Reference in New Issue
Block a user