Ingot molds drop bars out of the bottom on their own

Bars no longer get thrown up into the furnace, and F is no longer needed to
collect them. Blocked bars wait in the trough; the short stub stays for the
next firing; F is optional upkeep (clean, chip slag, rake).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 19:00:12 -04:00
co-authored by Claude Opus 5.5
parent 6676d99c66
commit de677b49c5
15 changed files with 140 additions and 68 deletions
+41 -27
View File
@@ -1,4 +1,4 @@
// Molds: cavities that fill with molten metal (or glass) and are knocked out as bars.
// Molds: cavities for castings; ingot troughs drop bars out of the bottom.
// ---------- Molds ----------
function moldCellsAt(kind, x, y) {
const md = MOLDS[kind]; const walls = [];
@@ -68,7 +68,7 @@ function cavityState(cav) {
return { st, fill: (solid + liq) / n, metal, flaw };
}
// The ingot trough: ready as soon as at least one bar's worth has set and nothing is still molten.
// It is forgiving: slag, ash or ore that got in is skimmed off when you knock the ingot out.
// Bars drop automatically; the short stub stays on the floor. F cleans out slag and grit.
function troughState(mo) {
let solid = 0, liq = 0, junk = 0, metal = -1, mixed = false;
for (const i of mo.cavs[0]) {
@@ -159,13 +159,40 @@ function unplugMold(mo) {
return { metal, chipped: got.dross || 0, raked: rakeAbove(mo) };
}
const grains = n => `${n} ${n === 1 ? 'grain' : 'grains'}`;
const barWord = (m, n) => m === GLASS ? (n === 1 ? 'glass brick' : 'glass bricks') : n === 1 ? 'bar' : 'bars';
function ejectIngot(mo) {
let r = troughState(mo), n = 0;
const metal = r.metal, x = mo.x + (mo.w >> 1), y = mo.y + mo.h;
if (r.st === 'ready') {
let T = 0, solid = 0, free = false;
for (const i of mo.cavs[0]) if (SOLIDMETAL[mat[i]] && castMix(metal, mat[i]) === metal) { T += temp[i]; solid++; }
T /= Math.max(1, solid);
for (let k = 0; k < 3 && n < r.bars; k++) {
const sx = mo.x + 1 + k * 4;
if (!entFreeAt(sx, y)) continue;
free = true;
if (spawnBar(BAR_OF[metal], sx, y, (rnd() - 0.5) * 0.15, 0.2, T)) n++;
}
if (n) {
// Take from the top so the short stub stays on the trough floor.
let take = n * GRAINS_PER_BAR;
for (const i of mo.cavs[0].slice().sort((a, b) => a - b)) if (take > 0 && SOLIDMETAL[mat[i]] && castMix(metal, mat[i]) === metal) { setCell(i, EMPTY, AMB[(i / W) | 0], 0); take--; }
const first = stats.cast === 0;
stats.bars += n; stats.cast++; mo.blockedSaid = false;
emit({ t: 'sfx', s: 'cast' });
emit({ t: 'ingot_drop', mold: mo.id, metal, bars: n, x, y, first });
r = troughState(mo);
} else if (!free && !mo.blockedSaid) { mo.blockedSaid = true; emit({ t: 'ingot_blocked', mold: mo.id, x, y }); }
}
if (r.st === 'empty') mo.blockedSaid = false;
mo.ready = []; if (r.st === 'ready') for (let k = 0; k < r.bars; k++) mo.ready.push(k);
mo.state = r.st; mo.fill = r.fill; mo.metal = r.metal; mo.flaw = r.flaw;
return n;
}
function checkMolds() {
for (const mo of molds) {
if (mo.kind === 'ingot') {
const r = troughState(mo);
mo.ready = []; if (r.st === 'ready') for (let k = 0; k < r.bars; k++) mo.ready.push(k);
if (r.st === 'ready' && mo.state !== 'ready') emit({ t: 'cast_ready', mold: mo.id, kind: mo.kind, metal: r.metal, bars: r.bars, x: mo.x + (mo.w >> 1), y: mo.y });
mo.state = r.st; mo.fill = r.fill; mo.metal = r.metal; mo.flaw = r.flaw;
ejectIngot(mo);
continue;
}
const res = mo.cavs.map(cavityState);
@@ -213,28 +240,15 @@ function collectMold(mo) {
return 'Knocked the mold clean.' + knockNote(scrap, g.other, g.dross + u.chipped, u.raked);
}
let msg = '';
if (mo.kind === 'ingot' && mo.state === 'ready') {
const n = ejectIngot(mo);
return n ? `Dropped ${n} ${barWord(mo.metal, n)} out of the bottom of the mold.` : 'Bars drop out of the bottom of the mold. Leave one open block under it, with a belt below that to carry them off.';
}
if (mo.kind === 'ingot') {
const cav = mo.cavs[0];
let solid = 0, T = 0;
const m = mo.metal;
if (mo.state === 'ready') for (const i of cav) if (SOLIDMETAL[mat[i]]) { solid++; T += temp[i]; }
T /= Math.max(1, solid);
const bars = Math.floor(solid / GRAINS_PER_BAR);
// the ingot snaps into bars that pop up and out of the trough; take the metal for them first
let take = bars * GRAINS_PER_BAR;
for (const i of cav.slice().sort((a, b) => b - a)) if (take > 0 && SOLIDMETAL[mat[i]] && castMix(m, mat[i]) === m) { setCell(i, EMPTY, AMB[(i / W) | 0], 0); take--; }
let n = 0;
for (let k = 0; k < bars; k++) {
const e = spawnBar(BAR_OF[m], mo.x + 1 + k * 4, mo.y - 3, (k - (bars - 1) / 2) * 0.3 + (rnd() - 0.5) * 0.15, -0.55, T);
if (e) n++; else bagAdd(BAR_OF[m], 1, true);
}
// the stub too short for a bar, and anything else that got in, are cleared out: the trough is left clean
const u = unplugMold(mo), g = tally(clearCavity(cav));
stats.bars += n; if (n) stats.cast++;
mo.state = 'empty'; mo.ready = [];
emit({ t: 'sfx', s: n ? 'cast' : 'ui' });
const word = m === GLASS ? (n === 1 ? 'glass brick' : 'glass bricks') : n === 1 ? 'bar' : 'bars';
return (n ? `Knocked out ${n} ${word}. Vacuum them up.` : 'Knocked the trough clean.') + knockNote(g.scrap + u.metal, g.other, g.dross + u.chipped, u.raked) + furnaceJunkHint(mo);
const u = unplugMold(mo), g = tally(clearCavity(mo.cavs[0]));
mo.state = 'empty'; mo.ready = []; mo.blockedSaid = false;
emit({ t: 'sfx', s: 'ui' });
return 'Knocked the trough clean.' + knockNote(g.scrap + u.metal, g.other, g.dross + u.chipped, u.raked) + furnaceJunkHint(mo);
}
if (mo.state === 'short' && !(mo.knockAsk != null && tick - mo.knockAsk >= 0 && tick - mo.knockAsk < 300)) {
// an unfinished casting can still be topped up, so the first press only says so
+2 -3
View File
@@ -72,7 +72,7 @@ const PIECES = [
{ id: 'dock', name: 'Trade dock', kind: 'machine', bw: 6, bh: 4, cost: [], hidden: true, fixed: true,
desc: 'Owned by the claim office. Anything that drops through the grate in its floor is sold on the spot. Build walls around it to funnel more in.' },
{ id: 'ingotmold', name: 'Ingot mold', kind: 'mold', mold: 'ingot', variants: 'wall',
desc: 'A long trough. Pour molten metal in, let it set, press F: it snaps into bars of 8 grains, up to 3.' },
desc: 'A long trough. Pour molten metal in: bars of 8 grains drop out of the bottom when set, up to 3. Leave one open block below it; a belt under that carries them off. F cleans the trough, chips off slag and rakes the furnace grate.' },
{ id: 'bitmold', name: 'Bit mold', kind: 'mold', mold: 'bit', variants: 'wall',
desc: 'A drill-bit-shaped cavity. Cast a harder metal in it to upgrade your drill.' },
{ id: 'tankmold', name: 'Tank mold', kind: 'mold', mold: 'tank', variants: 'wall',
@@ -86,8 +86,7 @@ const WHEEL_K = 0.32, ENGINE_K = 40;
const MOLDS = {
ingot: {
// one long trough: metal runs along it and sets level; knocking it out
// snaps the ingot into bars of 8 grains each
// one long trough: metal sets level and drops bars of 8 grains below
name: 'Ingot mold', rows: [
'................',
'#oooooooooooooo#',
+2 -2
View File
@@ -15,7 +15,7 @@ function smelterBlueprint(kind, count, ch, wall) {
}
const STARTER_DESIGNS = [
{ id: 'smelter1', name: 'Copper smelter', bp: () => smelterBlueprint('ingot', 1, 3, RSTONE),
desc: 'Stone furnace over an ingot mold. Charge it with about 50 copper ore and 50 coal, mixed (or the ore first with the coal on top), and light the coal. Makes 3 bars a firing. Press F on the mold to knock the bars out: that also rakes the slag off the grate, so it is ready to charge again. Leftover copper goes to your bag as scrap; throw it back in with the next charge.' },
desc: 'Stone furnace over an ingot mold. Charge it with about 50 copper ore and 50 coal, mixed (or the ore first with the coal on top), and light the coal. Makes 3 bars a firing. Bars drop out of the bottom of the mold onto whatever is under it; leave one open block under it, and a belt below that carries them off. Leftover copper stays for the next firing. F on the mold is optional: it cleans the trough, chips off slag and rakes the furnace grate.' },
{ id: 'bitfurnace', name: 'Bit casting furnace', bp: () => smelterBlueprint('bit', 1, 3, RSTONE),
desc: 'Stone furnace over a bit mold. Charge it with about 70 copper ore and 70 coal, mixed (or the coal on top), and light the coal. Press F once the bit has set. For iron, build it from brick and blow air in with a fan.' },
];
@@ -28,7 +28,7 @@ const MILESTONES = [
{ 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: tick both in your bag and pick Ticked mix with Q/E, and right click blows an even mix.' },
{ id: 'bars', title: 'Copper bars', msg: 'Bars sell for far more than the ore in them, and make metal wall blocks.', hint: 'Build an Ingot mold (Build, 3) right under the furnace with a floor of clay Grates between them: molten copper drips through, while the charge and the thick slag stay up. When the bars set, press F on the mold: the bars pop out and the grate is raked clean of slag. Then vacuum up the bars. Copper that sets in the furnace melts again next firing.' },
{ id: 'bars', title: 'Copper bars', msg: 'Bars sell for far more than the ore in them, and make metal wall blocks.', hint: 'Build an Ingot mold (Build, 3) right under the furnace with a floor of clay Grates between them: molten copper drips through, while the charge and the thick slag stay up. When the bars set, they drop out of the bottom of the mold onto whatever is under it; a belt carries them off. Leave space below, or vacuum up the bars. F on the mold is optional: it cleans the trough, chips off slag and rakes the furnace grate. Copper that sets in the furnace melts again next firing.' },
{ id: 'bit1', title: 'Copper drill bit', hint: 'Cast copper in a Bit mold. Building the furnace right on top works. A Grate over the funnel keeps the charge out. Let it set, then press F.', reward: 'Copper bit. You can now dig iron ore.' },
{ id: 'auto', title: 'Moving parts', msg: 'Machines can now haul for you. Feed furnaces automatically, and lift ore out of your mines.', hint: 'Belts carry grains and bars resting on them. Screw tubes push loose material along (never liquids); stacked pointing up they lift it out of a mine. A Filter lets one material fall through and carries the rest along, so you can sort ore from rubble. Move 300 grains with machines.' },
{ id: 'glass', title: 'Glass', hint: 'Sand melts near 1300°C. Still air will not get a fire that hot: point a Fan into the fuel. Molten glass runs through a grate like metal, so cast it in an Ingot mold for glass bricks, which sell well.', reward: 'Flask unlocked. The Vacuum can suck up and blow out liquids.' },