159 lines
4.9 KiB
JavaScript
159 lines
4.9 KiB
JavaScript
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|