From 24886c2752548f1c32ed54968a7bfdf2b1fe38ea Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 16 Aug 2026 00:46:57 -0700 Subject: fire changes + smoke --- src/sim/materials/fire.rs | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'src/sim/materials/fire.rs') diff --git a/src/sim/materials/fire.rs b/src/sim/materials/fire.rs index b155986..3c686fe 100644 --- a/src/sim/materials/fire.rs +++ b/src/sim/materials/fire.rs @@ -21,25 +21,28 @@ impl FireCellView for Cell { } } +// TODO optimize number of rng calls? #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { let ticks_lived = ctx.cell.get_ticks_lived(); // 2 seconds if ticks_lived > 240 { - // kill ourselves, with a chance to turn into ash - if ctx.rng.random_range(0.0..1.0) > 0.8 { - // TODO ash material - ctx.set_cell(0, 0, Cell::from_material(MaterialId::Sand)); - } else { - ctx.set_cell(0, 0, Cell::void()); + // we have a chance to live longer--roughly 50% chance of living an extra second + if ctx.rng.random_range(0.0..1.0) > 0.995 { + // kill ourselves, with a chance to turn into ash + if ctx.rng.random_range(0.0..1.0) > 0.8 { + // TODO ash material + ctx.set_cell(0, 0, Cell::from_material(MaterialId::Sand)); + } else { + ctx.set_cell(0, 0, Cell::void()); + } + return; } - return; } - // 4 times in our lifespan, try to spread in a random direction - // since it's random, fire may die out if there's nothing in that direction - // a 1-thick line of flammable cells has a 31% chance to die each iteration - if ticks_lived % 60 == 0 { + // at an average of 4 times per lifespan, try to spread + // 1/60 * 240 = 4 + if ctx.rng.random_range(0.0..1.0) > (59.0 / 60.0) { let (dx, dy) = (ctx.rng.random_range(-1..=1), ctx.rng.random_range(-1..=1)); if let Some(target) = ctx.get_cell(dx, dy) && target.is_flammable() @@ -48,6 +51,27 @@ pub fn sim_update(ctx: &mut UpdateCtx) { } } + // 8 times in our lifespan, emit smoke + if ticks_lived % 30 == 0 { + if let Some(target) = ctx.get_cell(0, -1) + && target.material == MaterialId::Void + { + for (dx, dy) in [ + (0, -1), + (1 - ctx.seqno_parity as i32 * 2, 0), + (-1 + ctx.seqno_parity as i32 * 2, 0), + (0, 1), + ] { + if let Some(target) = ctx.get_cell(dx, dy) + && target.material == MaterialId::Void + { + ctx.set_cell(dx, dy, Cell::from_material(MaterialId::Smoke)); + break; + } + } + } + } + ctx.cell.set_ticks_lived(ticks_lived + 1); ctx.set_cell(0, 0, *ctx.cell); } -- cgit v1.3.1