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
use bevy_app::prelude::*;
use bevy_doryen::doryen::{color_mul, color_scale, Color};
use bevy_doryen::prelude::*;
use bevy_ecs::prelude::*;

use super::super::level::LevelMap;
use super::super::light::{LightMap, LIGHT_COEF};
use super::super::{is_running, RenderSet};
use super::Position;

pub struct CharacterPlugin;
impl Plugin for CharacterPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(
            Render,
            render_character
                .in_set(RenderSet::Entities)
                .run_if(is_running()),
        );
    }
}

#[derive(Component)]
pub struct Character {
    /// console character for this entity
    pub ch: u16,
    pub name: String,
    pub color: Color,
    pub light: bool,
}

fn render_character(
    mut root_console: ResMut<RootConsole>,
    query: Query<(&Character, &Position)>,
    level_map: Res<LevelMap>,
    light_map: NonSend<LightMap>,
) {
    for (character, position) in &query {
        if !level_map
            .0
            .is_in_fov(position.x as usize, position.y as usize)
        {
            continue;
        }
        let (color, penumbra) = if character.light {
            (character.color, false)
        } else {
            let light = light_map
                .0
                .pixel(position.x as u32, position.y as u32)
                .unwrap();

            let penumbra = is_penumbra(light, 100);
            let mut color = color_mul(character.color, light);
            if penumbra {
                color = color_scale(color, LIGHT_COEF);
            }
            (color, penumbra)
        };
        root_console.ascii(
            position.character_x(),
            position.character_y(),
            if penumbra { '?' as u16 } else { character.ch },
        );
        root_console.fore(position.character_x(), position.character_y(), color);
    }
}

fn is_penumbra(color: Color, level: usize) -> bool {
    (color.0 as usize + color.1 as usize + color.2 as usize) < level
}