1use std::collections::VecDeque;
2use std::sync::atomic::{AtomicUsize, Ordering};
3
4static SMOKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
5
6#[derive(Clone, Copy)]
7pub struct Particle {
8 pub x: i32,
9 pub y: i32,
10 pub pattern: usize,
11 pub kind: usize,
12}
13
14pub struct Smoke {
15 particles: VecDeque<Particle>,
16 should_generate: bool,
17}
18
19thread_local! {
20 static SMOKE: std::cell::RefCell<Smoke> = const {
21 std::cell::RefCell::new(Smoke {
22 particles: VecDeque::new(),
23 should_generate: false,
24 })
25 };
26}
27
28pub fn set_generation_gate(should_gen: bool) {
29 SMOKE.with(|s| {
30 let mut smoke = s.borrow_mut();
31 smoke.should_generate = should_gen;
32 });
33}
34
35pub fn add_smoke(x: i32, y: i32) {
36 SMOKE.with(|s| {
37 let mut smoke = s.borrow_mut();
38 if smoke.should_generate && smoke.particles.len() < 1000 {
39 let counter = SMOKE_COUNTER.fetch_add(1, Ordering::SeqCst);
40 let kind = counter % 2;
41 smoke.particles.push_back(Particle {
42 x,
43 y,
44 pattern: 0,
45 kind,
46 });
47 }
48 });
49}
50
51pub fn update_smoke() {
52 SMOKE.with(|s| {
53 let mut smoke = s.borrow_mut();
54 if !smoke.should_generate {
55 return;
56 }
57 for particle in &mut smoke.particles {
58 use crate::train::ascii::{SMOKE_DY, SMOKE_DX};
59
60 let dy = SMOKE_DY[particle.pattern];
61 let dx = SMOKE_DX[particle.pattern];
62
63 particle.y -= dy;
64 particle.x += dx;
65 particle.pattern += 1;
66 }
67 smoke.particles.retain(|p| p.pattern < 16);
68 });
69}
70
71pub fn get_smoke_particles() -> Vec<Particle> {
72 SMOKE.with(|s| {
73 let smoke = s.borrow();
74 smoke.particles.iter().copied().collect()
75 })
76}
77
78pub fn clear_smoke() {
79 SMOKE.with(|s| {
80 let mut smoke = s.borrow_mut();
81 smoke.particles.clear();
82 });
83}