// 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); } }