2026-10-22 14:05:51 +00:00
|
|
|
import { grid, cols, rows } from './state.js';
|
|
|
|
|
import { config } from './config.js';
|
|
|
|
|
import { move, swap } from './actions.js';
|
|
|
|
|
import { explode } from './explosive.js';
|
2026-10-22 14:45:19 +00:00
|
|
|
import { createCell } from './physics.js';
|
|
|
|
|
|
|
|
|
|
const dxs = [0, 0, -1, 1];
|
|
|
|
|
const dys = [1, -1, 0, 0];
|
2026-10-22 14:05:51 +00:00
|
|
|
|
|
|
|
|
export function updateAcid(x, y, cell) {
|
2026-10-22 14:45:19 +00:00
|
|
|
// 1. Corrosive reactions with neighbors
|
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
|
|
|
const nx = x + dxs[i];
|
|
|
|
|
const ny = y + dys[i];
|
2026-10-22 14:05:51 +00:00
|
|
|
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && grid[nx][ny]) {
|
|
|
|
|
const t = grid[nx][ny].type;
|
2026-10-22 14:45:19 +00:00
|
|
|
if (t === 'rock' || t === 'wood' || t === 'dirt' || t === 'sand' || t === 'plant' || t === 'grass' || t === 'ice' || t === 'oil') {
|
2026-10-22 14:05:51 +00:00
|
|
|
if (config.acid.dissolve[t] && Math.random() < config.acid.dissolveChance) {
|
2026-10-22 14:45:19 +00:00
|
|
|
grid[nx][ny] = createCell('smoke'); // Dissolves into toxic smoke
|
|
|
|
|
grid[x][y] = null; // Acid is consumed
|
2026-10-22 14:05:51 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (t === 'explosive') {
|
|
|
|
|
if (config.acid.explodeTNT) {
|
|
|
|
|
explode(nx, ny);
|
|
|
|
|
grid[x][y] = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-10-22 14:45:19 +00:00
|
|
|
} else if (t === 'lava') {
|
|
|
|
|
grid[x][y] = createCell('steam');
|
|
|
|
|
grid[nx][ny] = createCell('rock');
|
|
|
|
|
return;
|
2026-10-22 14:05:51 +00:00
|
|
|
} else if (t === 'water') {
|
2026-10-22 14:45:19 +00:00
|
|
|
if (config.acid.dissolve.water && Math.random() < 0.02) {
|
|
|
|
|
grid[nx][ny] = createCell('acid'); // Invert/infect water into acid
|
2026-10-22 14:05:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-10-22 14:45:19 +00:00
|
|
|
|
|
|
|
|
// 2. Straight fall
|
2026-10-22 14:05:51 +00:00
|
|
|
const below = y + 1;
|
|
|
|
|
if (below >= rows) return;
|
|
|
|
|
|
|
|
|
|
const belowCell = grid[x][below];
|
|
|
|
|
if (!belowCell) {
|
|
|
|
|
move(x, y, x, below);
|
2026-10-22 14:45:19 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Acid is dense: sinks through water & oil if not dissolving them
|
|
|
|
|
if (belowCell.type === 'water' || belowCell.type === 'oil') {
|
|
|
|
|
if (!config.acid.dissolve[belowCell.type] && Math.random() < config.acid.sinkChance) {
|
2026-10-22 14:05:51 +00:00
|
|
|
swap(x, y, x, below);
|
2026-10-22 14:45:19 +00:00
|
|
|
return;
|
2026-10-22 14:05:51 +00:00
|
|
|
}
|
2026-10-22 14:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. Diagonal fall
|
|
|
|
|
const canDownLeft = x > 0 && (!grid[x - 1][below] || isPermeableFluid(grid[x - 1][below]));
|
|
|
|
|
const canDownRight = x < cols - 1 && (!grid[x + 1][below] || isPermeableFluid(grid[x + 1][below]));
|
|
|
|
|
|
|
|
|
|
if (canDownLeft && canDownRight) {
|
|
|
|
|
const targetX = Math.random() < 0.5 ? x - 1 : x + 1;
|
|
|
|
|
executeAcidStep(x, y, targetX, below);
|
|
|
|
|
return;
|
|
|
|
|
} else if (canDownLeft) {
|
|
|
|
|
executeAcidStep(x, y, x - 1, below);
|
|
|
|
|
return;
|
|
|
|
|
} else if (canDownRight) {
|
|
|
|
|
executeAcidStep(x, y, x + 1, below);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. Fast horizontal fluid dispersion
|
|
|
|
|
const maxDisp = config.acid.dispersion || 4;
|
|
|
|
|
const dir = Math.random() < 0.5 ? 1 : -1;
|
|
|
|
|
|
|
|
|
|
for (const d of [dir, -dir]) {
|
|
|
|
|
let targetX = x;
|
|
|
|
|
|
|
|
|
|
for (let step = 1; step <= maxDisp; step++) {
|
|
|
|
|
const nx = x + d * step;
|
|
|
|
|
if (nx < 0 || nx >= cols) break;
|
|
|
|
|
|
|
|
|
|
const c = grid[nx][y];
|
|
|
|
|
if (!c) {
|
|
|
|
|
targetX = nx;
|
|
|
|
|
if (y + 1 < rows && !grid[nx][y + 1]) {
|
|
|
|
|
targetX = nx;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if ((c.type === 'water' || c.type === 'oil') && !config.acid.dissolve[c.type]) {
|
|
|
|
|
if (Math.random() < config.acid.sinkChance) {
|
|
|
|
|
targetX = nx;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-10-22 14:05:51 +00:00
|
|
|
}
|
2026-10-22 14:45:19 +00:00
|
|
|
|
|
|
|
|
if (targetX !== x) {
|
|
|
|
|
executeAcidStep(x, y, targetX, y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isPermeableFluid(cell) {
|
|
|
|
|
return cell && (cell.type === 'water' || cell.type === 'oil') && !config.acid.dissolve[cell.type];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function executeAcidStep(x1, y1, x2, y2) {
|
|
|
|
|
if (grid[x2][y2]) {
|
|
|
|
|
swap(x1, y1, x2, y2);
|
|
|
|
|
} else {
|
|
|
|
|
move(x1, y1, x2, y2);
|
2026-10-22 14:05:51 +00:00
|
|
|
}
|
|
|
|
|
}
|