1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
use rand::RngExt;
use crate::{
content::materials::MaterialId,
sim::{
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
}
|