92 lines
No EOL
3.1 KiB
JavaScript
92 lines
No EOL
3.1 KiB
JavaScript
import { grid, cols, rows } from './state.js';
|
|
import { config } from './config.js';
|
|
import { move } from './actions.js';
|
|
import { createCell } from './physics.js';
|
|
import { explode } from './explosive.js';
|
|
|
|
const dxs = [0, 0, -1, 1];
|
|
const dys = [1, -1, 0, 0];
|
|
|
|
export function updateFire(x, y, cell) {
|
|
if (cell.lifespan === undefined) {
|
|
cell.lifespan = Math.floor(Math.random() * 20) + 10;
|
|
cell.maxLife = cell.lifespan;
|
|
}
|
|
|
|
cell.lifespan--;
|
|
|
|
// Color shift as fire cools: yellow -> orange -> ember red
|
|
const lifeRatio = cell.lifespan / (cell.maxLife || 25);
|
|
if (lifeRatio > 0.6) {
|
|
cell.u32Color = 0xFF70F0FF; // Bright yellow-white (ABGR)
|
|
} else if (lifeRatio > 0.3) {
|
|
cell.u32Color = 0xFF0080FF; // Intense flame orange
|
|
} else {
|
|
cell.u32Color = 0xFF0025D0; // Deep ember red
|
|
}
|
|
|
|
// Death / decay -> spawn smoke
|
|
if (cell.lifespan <= 0 || Math.random() < config.fire.burnChance) {
|
|
if (Math.random() < 0.65) {
|
|
grid[x][y] = createCell('smoke');
|
|
} else {
|
|
grid[x][y] = null;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Extinguish if suffocated by solid matter
|
|
let airNeighbor = false;
|
|
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 n = grid[nx][ny];
|
|
if (!n || n.type === 'steam' || n.type === 'smoke') {
|
|
airNeighbor = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!airNeighbor && Math.random() < 0.2) {
|
|
grid[x][y] = null;
|
|
return;
|
|
}
|
|
|
|
// Spread to flammable 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 n = grid[nx][ny];
|
|
if (n) {
|
|
const nt = n.type;
|
|
if (nt === 'water' || nt === 'ice') {
|
|
grid[x][y] = null; // Fire extinguished
|
|
grid[nx][ny] = createCell('steam');
|
|
return;
|
|
} else if (nt === 'explosive') {
|
|
explode(nx, ny);
|
|
return;
|
|
} else if (nt === 'oil') {
|
|
grid[nx][ny] = createCell('fire');
|
|
} else if (nt === 'plant' && Math.random() < config.plant.burnChance) {
|
|
grid[nx][ny] = createCell('fire');
|
|
} else if (nt === 'grass' && Math.random() < config.grass.burnChance) {
|
|
grid[nx][ny] = createCell('fire');
|
|
} else if (nt === 'wood' && Math.random() < config.wood.burnChance) {
|
|
grid[nx][ny] = createCell('fire');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rise / flicker randomly upwards
|
|
const dx = Math.floor(Math.random() * 3) - 1;
|
|
const dy = -Math.floor(Math.random() * 2); // Rise: 0 or -1
|
|
const nx = x + dx;
|
|
const ny = y + dy;
|
|
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && !grid[nx][ny]) {
|
|
move(x, y, nx, ny);
|
|
}
|
|
} |