57 lines
2.1 KiB
JavaScript
57 lines
2.1 KiB
JavaScript
// Each rack block owns its bars; only the bottom of a column releases them.
|
|
const RACK_CAP = 50;
|
|
let rackState = new Map();
|
|
function newRack() { return { q: [], n: 0, open: false, wait: 0 }; }
|
|
function rackTop(b) { while (b >= BW && blockP[b - BW] === BP_RACK) b -= BW; return b; }
|
|
function rackBottom(b) { while (b + BW < NB && blockP[b + BW] === BP_RACK) b += BW; return b; }
|
|
function rackPush(s, m, n) {
|
|
const last = s.q[s.q.length - 1];
|
|
if (last && last[0] === m) last[1] += n; else s.q.push([m, n]);
|
|
s.n += n;
|
|
}
|
|
function rackShift(s, n) {
|
|
s.q[0][1] -= n; s.n -= n;
|
|
if (!s.q[0][1]) s.q.shift();
|
|
}
|
|
// Called with the moving bar unmarked, after its ordinary collision handling.
|
|
function rackIntake(e) {
|
|
const y = e.iy + BAR_H;
|
|
if (e.vy !== 0 || Math.abs(e.vx) >= 0.05 || y >= H || y % BS) return false;
|
|
for (let x = Math.max(0, e.ix); x < Math.min(W, e.ix + BAR_W); x += BS - x % BS) {
|
|
const b = (y / BS) * BW + Math.floor(x / BS), left = (b % BW) * BS;
|
|
if (blockP[b] !== BP_RACK || b >= BW && blockP[b - BW] === BP_RACK || Math.min(e.ix + BAR_W, left + BS) - Math.max(e.ix, left) < BAR_W / 2) continue;
|
|
for (let q = rackBottom(b); q >= b; q -= BW) {
|
|
const s = rackState.get(q);
|
|
if (s.n < RACK_CAP) { rackPush(s, e.m, 1); return true; }
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function rackRefill(b) {
|
|
const top = rackTop(b);
|
|
for (let q = b; q > top; q -= BW) {
|
|
const lower = rackState.get(q);
|
|
for (let above = q - BW; above >= top && lower.n < RACK_CAP; above -= BW) {
|
|
const upper = rackState.get(above);
|
|
while (lower.n < RACK_CAP && upper.n) {
|
|
const n = Math.min(RACK_CAP - lower.n, upper.q[0][1]);
|
|
rackPush(lower, upper.q[0][0], n); rackShift(upper, n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function rackTick() {
|
|
for (const [b, s] of rackState) {
|
|
if (b + BW < NB && blockP[b + BW] === BP_RACK) continue;
|
|
if (!s.open) continue;
|
|
if (!s.n) rackRefill(b);
|
|
if (!s.n) continue;
|
|
if (s.wait < 20) s.wait++;
|
|
if (s.wait < 20) continue;
|
|
const x = (b % BW) * BS, y = (((b / BW) | 0) + 1) * BS;
|
|
if (!entFreeAt(x, y) || !spawnBar(s.q[0][0], x, y, 0, 0)) continue;
|
|
rackShift(s, 1); s.wait = 0;
|
|
rackRefill(b);
|
|
}
|
|
}
|