88 lines
4.5 KiB
JavaScript
88 lines
4.5 KiB
JavaScript
// 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; bag full, excess dropped here.') : 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; press F 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);
|
|
// ingot molds empty themselves: F passes them by
|
|
if (mo && mo.kind !== 'ingot') { 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 '';
|
|
}
|