import { grid, cols, rows } from './state.js'; import { config } from './config.js'; import { move, swap } from './actions.js'; import { updateDirt } from './dirt.js'; import { updateWater } from './water.js'; import { updateAcid } from './acid.js'; import { updateSteam } from './steam.js'; import { updatePlant } from './plant.js'; import { updateFire } from './fire.js'; import { updateExplosive, explode } from './explosive.js'; export function spawnCell(x, y, type) { if (x >= 0 && x < cols && y >= 0 && y < rows) { const target = grid[x][y]; // Manual Detonation if (target && target.type === 'explosive' && type === 'fire') { if (!config.time.paused) { explode(x, y); } return; } // Check if target is a fluid/gas that can be displaced const isDisplaceable = target && (target.type === 'water' || target.type === 'acid' || target.type === 'steam'); if (!target || (isDisplaceable && type !== target.type)) { // If it's displaceable, try to push it aside if (isDisplaceable) { const neighbors = [[-1,0], [1,0], [0,-1], [0,1]]; neighbors.sort(() => Math.random() - 0.5); for (let n of neighbors) { const nx = x + n[0]; const ny = y + n[1]; if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && !grid[nx][ny]) { grid[nx][ny] = target; // Move fluid here target.updated = true; // Add Ripple Velocity target.vx = (target.vx || 0) + n[0] * 2; target.vy = (target.vy || 0) + n[1] * 2 - 1; break; } } } grid[x][y] = createCell(type); } } } function createCell(type) { const colors = { dirt: '#ffaa00', plant: '#228B22', water: '#0000FF', fire: '#FF5500', rock: '#808080', wood: '#8B4513', explosive: '#8B0000', acid: '#7FFF00', steam: '#E0FFFF' }; return { type, color: colors[type] || '#FFF', updated: false }; } export function update() { for (let x = 0; x < cols; x++) { for (let y = 0; y < rows; y++) { if (grid[x][y]) grid[x][y].updated = false; } } for (let y = rows - 1; y >= 0; y--) { for (let x = 0; x < cols; x++) { if (grid[x][y] && !grid[x][y].updated) { updateCell(x, y); } } } } function updateCell(x, y) { const cell = grid[x][y]; cell.updated = true; // Physics for tossed particles (Explosions/Velocity) if (cell.vx || cell.vy) { applyVelocity(x, y, cell); // If velocity moved it, we might stop here or continue depending on logic. // For now, if it moved, we consider it updated for this frame. if (!grid[x][y] || grid[x][y] !== cell) return; } const type = cell.type; if (type === 'dirt') { updateDirt(x, y, cell); } else if (type === 'water') { updateWater(x, y, cell); } else if (type === 'fire') { updateFire(x, y, cell); } else if (type === 'steam') { updateSteam(x, y, cell); } else if (type === 'acid') { updateAcid(x, y, cell); } else if (type === 'plant') { updatePlant(x, y, cell); } else if (type === 'explosive') { updateExplosive(x, y, cell); } } function applyVelocity(x, y, cell) { cell.vx = cell.vx || 0; cell.vy = cell.vy || 0; if (cell.type === 'steam') { cell.vy -= 0.1; // Steam rises } else { cell.vy += config.global.gravity; } cell.vx *= config.global.drag; cell.vy *= config.global.drag; let nextX = Math.round(x + cell.vx); let nextY = Math.round(y + cell.vy); // Bounce off walls if (nextX < 0 || nextX >= cols) { cell.vx *= -0.5; nextX = x; } if (nextY < 0 || nextY >= rows) { cell.vy *= -0.3; nextY = y; } if (nextX >= 0 && nextX < cols && nextY >= 0 && nextY < rows) { const neighbor = grid[nextX][nextY]; if (!neighbor) { move(x, y, nextX, nextY); } else if (neighbor.type === 'steam') { swap(x, y, nextX, nextY); } else if (neighbor.type === 'water' || neighbor.type === 'dirt' || neighbor.type === 'acid') { // Collision with movable particles neighbor.vx = (neighbor.vx || 0) + cell.vx * 0.8; neighbor.vy = (neighbor.vy || 0) + cell.vy * 0.8; neighbor.vx += (Math.random() - 0.5); // Scatter neighbor.updated = true; cell.vx *= -0.4; cell.vy *= -0.4; } else { cell.vx *= -0.3; cell.vy *= -0.3; } } }