SandGame/lava.js

136 lines
4.3 KiB
JavaScript
Raw Permalink Normal View History

import { grid, cols, rows } from './state.js';
import { config } from './config.js';
import { move, swap } from './actions.js';
import { createCell } from './physics.js';
export function updateLava(x, y, cell) {
const dxs = [0, 0, -1, 1];
const dys = [-1, 1, 0, 0];
// Thermal interactions with neighbors
for (let i = 0; i < 4; i++) {
const nx = x + dxs[i];
const ny = y + dys[i];
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows) {
const neighbor = grid[nx][ny];
if (neighbor) {
const nt = neighbor.type;
if (nt === 'water') {
// Boils water into steam, and lava cools into rock
grid[nx][ny] = createCell('steam');
if (Math.random() < (config.lava?.coolingChance || 0.04)) {
grid[x][y] = createCell('rock');
return;
}
} else if (nt === 'ice') {
grid[nx][ny] = createCell('water');
} else if (nt === 'plant' || nt === 'grass' || nt === 'wood' || nt === 'oil') {
grid[nx][ny] = createCell('fire');
}
}
}
}
// Occasional surface cooling into rock
if (Math.random() < (config.lava?.coolingChance || 0.04) * 0.05) {
grid[x][y] = createCell('rock');
return;
}
// Spontaneous smoke/spark above
if (y > 0 && !grid[x][y - 1] && Math.random() < 0.003) {
grid[x][y - 1] = createCell(Math.random() < 0.5 ? 'smoke' : 'fire');
}
// 1. Straight fall
const below = y + 1;
if (below >= rows) return;
const belowCell = grid[x][below];
if (!belowCell) {
move(x, y, x, below);
return;
}
// Lava is dense: sinks rapidly through water, oil, and acid
if (belowCell.type === 'water') {
const sinkRate = config.lava?.sinkChance !== undefined ? config.lava.sinkChance : 0.7;
if (Math.random() < sinkRate) {
// Plunge into the water and boil water into rising steam
swap(x, y, x, below);
if (Math.random() < 0.5) {
grid[x][y] = createCell('steam');
}
if (Math.random() < (config.lava?.coolingChance || 0.04)) {
grid[x][below] = createCell('rock');
}
return;
}
} else if (belowCell.type === 'oil' || belowCell.type === 'acid') {
swap(x, y, x, below);
return;
}
// 2. Diagonal fall
const canDownLeft = x > 0 && (!grid[x - 1][below] || grid[x - 1][below].type === 'water');
const canDownRight = x < cols - 1 && (!grid[x + 1][below] || grid[x + 1][below].type === 'water');
if (canDownLeft && canDownRight) {
const targetX = Math.random() < 0.5 ? x - 1 : x + 1;
executeLavaStep(x, y, targetX, below);
return;
} else if (canDownLeft) {
executeLavaStep(x, y, x - 1, below);
return;
} else if (canDownRight) {
executeLavaStep(x, y, x + 1, below);
return;
}
// 3. Horizontal dispersion
const flowChance = config.lava?.flowChance !== undefined ? config.lava.flowChance : 0.4;
if (Math.random() < flowChance) {
const maxDisp = config.lava?.dispersion || 2;
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') {
targetX = nx;
break;
} else {
break;
}
}
if (targetX !== x) {
executeLavaStep(x, y, targetX, y);
return;
}
}
}
}
function executeLavaStep(x1, y1, x2, y2) {
if (grid[x2][y2]) {
if (grid[x2][y2].type === 'water') {
grid[x2][y2] = createCell('steam');
}
swap(x1, y1, x2, y2);
} else {
move(x1, y1, x2, y2);
}
}