Deepgrain Foundry: move from a claude.ai artifact to a local repository
The game as of artifact version 24, ready for local development with coding agents. - Source split from three large files into 52 small ones under src/sim, src/render and src/ui, joined in the order in src/manifest.json by build.py. The joined code is unchanged apart from comments; every headless suite gives the same output, and screenshots in both looks are pixel-identical to before. - Light tidying with no change in behaviour: one movement scan loop, shared hazard-stripe and belt shader helpers, unused code removed, a shared check helper for the test suites. - World files can be exported as an ordinary download outside claude.ai. - Tests: broken old scripts removed, experiments moved to tools/, test/run_all.py added. Tools: shot.py (repeatable screenshots), where.py, map.py. - Docs: AGENTS.md, CLAUDE.md, NOTES.md (the owner's to-do inbox), docs/PROJECT_MAP.md, DESIGN.md, TESTING.md, systems notes, the owner's requests and an agent log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K9kLmYADKSEjuwUN3rFxDA
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
// Player actions on built things: take back, place a machine or mold, gates, F to interact.
|
||||
// Take back whatever piece is at (x,y): machine, mold or block. Returns a message.
|
||||
function removePieceAt(x, y) {
|
||||
droppedLast = 0;
|
||||
const msg = removePieceAt0(x, y);
|
||||
return msg && droppedLast ? msg.replace('taken back.', 'taken back. Your bag is full, so the rest dropped where it stood.') : msg;
|
||||
}
|
||||
function removePieceAt0(x, y) {
|
||||
if (x < 0 || y < 0 || x >= W || y >= H) return '';
|
||||
const i = y * W + x;
|
||||
if (ghostBlocks.has(((y / BS) | 0) * BW + ((x / BS) | 0))) { ghostBlocks.delete(((y / BS) | 0) * BW + ((x / BS) | 0)); return 'Ghost removed.'; }
|
||||
const gbx = (x / BS) | 0, gby = (y / BS) | 0;
|
||||
for (let k = ghostMachines.length - 1; k >= 0; k--) { const g = ghostMachines[k], P = PIECE_BY_ID[g.type]; if (gbx >= g.bx && gby >= g.by && gbx < g.bx + P.bw && gby < g.by + P.bh) { ghostMachines.splice(k, 1); return 'Ghost removed.'; } }
|
||||
for (let k = ghostMolds.length - 1; k >= 0; k--) { const g = ghostMolds[k], md = MOLDS[g.kind]; if (gbx >= g.bx && gby >= g.by && gbx < g.bx + md.bw && gby < g.by + md.bh) { ghostMolds.splice(k, 1); return 'Ghost removed.'; } }
|
||||
if (mach[i] && machines[mach[i]]) {
|
||||
const P = PIECE_BY_ID[machines[mach[i]].type];
|
||||
if (P.fixed) return '';
|
||||
if (siloFull(machines[mach[i]])) return `Empty the silo first: it holds ${machines[mach[i]].sn.toLocaleString('en-US')} ${MD[machines[mach[i]].sm].name.toLowerCase()}. Press F on it to open its gate.`;
|
||||
removeMachine(mach[i], true, false); return `${P.name} taken back.`;
|
||||
}
|
||||
const mo = moldAt(x, y);
|
||||
if (mo) { removeMold(mo); return `${MOLDS[mo.kind].name} taken back.`; }
|
||||
const { bx, by } = blockOf(x, y), b = by * BW + bx;
|
||||
if (blockP[b]) { const nm = PIECE_BY_CODE[blockP[b]].name; removeBlock(bx, by); return `${nm} taken back.`; }
|
||||
return '';
|
||||
}
|
||||
function placeMachineAt(pid, dir, bx, by) {
|
||||
const P = PIECE_BY_ID[pid];
|
||||
const err = canPlaceMachine(pid, bx, by); if (err) return err;
|
||||
if (!canAfford(P.cost, 1)) return needText(P.cost, 1);
|
||||
payCost(P.cost, 1);
|
||||
addMachine(pid, bx, by, dir);
|
||||
stats.placed++;
|
||||
undoNote({ t: 'mach+', type: pid, bx, by });
|
||||
return '';
|
||||
}
|
||||
function placeMoldAt(kind, bx, by, wallLoose) {
|
||||
const err = canPlaceMold(kind, bx, by); if (err) return err;
|
||||
const r = addMold(kind, bx, by, wallLoose, false);
|
||||
if (typeof r !== 'string') undoNote({ t: 'mold+', kind, bx, by });
|
||||
return typeof r === 'string' ? r : '';
|
||||
}
|
||||
function toggleGateAt(x, y) {
|
||||
const i0 = y * W + x;
|
||||
if (!(mat[i0] === GATE || part[i0] === P_GOPEN)) return false;
|
||||
const open = mat[i0] === GATE; // currently closed -> open
|
||||
const seenS = new Set([i0]), st = [i0], cells = [];
|
||||
while (st.length && cells.length < 1600) {
|
||||
const i = st.pop(); cells.push(i);
|
||||
const cx = i % W;
|
||||
for (const j of [cx > 0 ? i - 1 : -1, cx < W - 1 ? i + 1 : -1, i - W, i + W]) {
|
||||
if (j < 0 || j >= N || seenS.has(j)) continue;
|
||||
if (mat[j] === GATE || part[j] === P_GOPEN) { seenS.add(j); st.push(j); }
|
||||
}
|
||||
}
|
||||
for (const i of cells) {
|
||||
const cx = i % W, cy = (i / W) | 0;
|
||||
if (open) { if (mat[i] === GATE) { mat[i] = EMPTY; flags[i] = 0; part[i] = P_GOPEN; } }
|
||||
else if (part[i] === P_GOPEN) {
|
||||
const m = mat[i];
|
||||
if (m !== EMPTY && PH[m] !== PH_GAS) {
|
||||
const u = i - W;
|
||||
if (u >= 0 && mat[u] === EMPTY && !part[u]) { mat[u] = m; temp[u] = temp[i]; life[u] = life[i]; flags[u] = flags[i]; }
|
||||
}
|
||||
part[i] = 0; mat[i] = GATE; flags[i] = 0; life[i] = 0;
|
||||
}
|
||||
wakeXY(cx, cy);
|
||||
}
|
||||
return open ? 'open' : 'closed';
|
||||
}
|
||||
function interactAt(x, y) {
|
||||
if (x < 0 || y < 0 || x >= W || y >= H) return '';
|
||||
const g = toggleGateAt(x, y);
|
||||
if (g) { emit({ t: 'sfx', s: 'gate' }); return g === 'open' ? 'Gate opened.' : 'Gate closed.'; }
|
||||
const mo = moldAt(x, y);
|
||||
if (mo) { const r = collectMold(mo); if (!r.startsWith('New') && !r.startsWith('Knocked')) emit({ t: 'sfx', s: 'ui' }); return r; }
|
||||
const pb = ((y / BS) | 0) * BW + ((x / BS) | 0);
|
||||
if (blockP[pb] === BP_PUMP || blockP[pb] === BP_OUTLET) {
|
||||
blockV[pb] ^= 4; emit({ t: 'sfx', s: 'ui' });
|
||||
return blockP[pb] === BP_PUMP ? (blockV[pb] & 4 ? 'Pump off.' : 'Pump on.') : (blockV[pb] & 4 ? 'Outlet closed.' : 'Outlet open.');
|
||||
}
|
||||
const id = mach[y * W + x];
|
||||
if (id && machines[id] && machines[id].type === 'silo') { const mm = machines[id]; mm.open = !mm.open; return mm.open ? (mm.sn ? 'Silo gate open.' : 'Silo gate open. It is empty.') : 'Silo gate shut.'; }
|
||||
if (id && machines[id] && machines[id].type === 'fan') { machines[id].on = !machines[id].on; powerDirty = true; return machines[id].on ? 'Fan on.' : 'Fan off.'; }
|
||||
return '';
|
||||
}
|
||||
Reference in New Issue
Block a user