From 350c74bc8ef61833be11bbb2bab6747245e3ae0d Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 23 Aug 2026 00:38:32 -0700 Subject: refactor out content --- src/content/materials/fire.rs | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/content/materials/fire.rs (limited to 'src/content/materials/fire.rs') diff --git a/src/content/materials/fire.rs b/src/content/materials/fire.rs new file mode 100644 index 0000000..483afbc --- /dev/null +++ b/src/content/materials/fire.rs @@ -0,0 +1,80 @@ +use rand::RngExt; + +use crate::{ + content::materials::MaterialId, + sim::{ + cell::cell::Cell, + cell_manager::sim::{PostUpdateAction, UpdateCtx}, + }, +}; + +pub trait FireCellView { + fn get_ticks_lived(self) -> u16; + fn set_ticks_lived(&mut self, ticks: u16) -> (); + fn is_flammable(self) -> bool; +} + +impl FireCellView for Cell { + fn get_ticks_lived(self) -> u16 { + self.data + } + fn set_ticks_lived(&mut self, ticks: u16) { + self.data = ticks; + } + // this could be a property of the material def, I think it's better here for now + fn is_flammable(self) -> bool { + [MaterialId::Wood].contains(&self.material) + } +} + +// TODO optimize number of rng calls? +// TODO wtf is fire +#[inline] +pub fn sim_update(ctx: &mut UpdateCtx) -> PostUpdateAction { + let ticks_lived = ctx.cell.get_ticks_lived(); + // 2 seconds + if ticks_lived > 240 { + // we have a chance to live longer--roughly ?% chance of living an extra second + if ctx.rng.random_range(0.0..1.0) > 0.9 { + // kill ourselves, with a chance to turn into ash + ctx.set_cell(0, 0, Cell::void()); + // the updater should take no action since we already killed ourselves + return PostUpdateAction::None; + } + } + + // 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() + { + ctx.set_cell(dx, dy, Cell::from_material(MaterialId::Fire)); + } + } + + // 8 times in our lifespan, emit smoke + if ticks_lived.is_multiple_of(30) + && 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); + // apply our new lifespan + PostUpdateAction::Apply +} -- cgit v1.3.1