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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use super::*;
use crate::Land;
use common::generation::EntityInfo;
use gen::render_prefab;
use rand::prelude::*;
use vek::*;

pub struct Barn {
    /// Tile position of the door tile
    pub door_tile: Vec2<i32>,
    /// Axis aligned bounding region for the house
    bounds: Aabr<i32>,
    /// Approximate altitude of the door tile
    pub(crate) alt: i32,
    is_desert: bool,
}

impl Barn {
    pub fn generate(
        land: &Land,
        _rng: &mut impl Rng,
        site: &Site,
        door_tile: Vec2<i32>,
        door_dir: Vec2<i32>,
        tile_aabr: Aabr<i32>,
        is_desert: bool,
    ) -> Self {
        let door_tile_pos = site.tile_center_wpos(door_tile);
        let bounds = Aabr {
            min: site.tile_wpos(tile_aabr.min),
            max: site.tile_wpos(tile_aabr.max),
        };
        Self {
            door_tile: door_tile_pos,
            bounds,
            alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2,
            is_desert,
        }
    }
}

impl Structure for Barn {
    #[cfg(feature = "use-dyn-lib")]
    const UPDATE_FN: &'static [u8] = b"render_barn\0";

    #[cfg_attr(feature = "be-dyn-lib", export_name = "render_barn")]
    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
        let base = self.alt;
        let center = self.bounds.center();

        let length = 18;
        let width = 6;

        // solid dirt to fill any gaps underneath the barn
        let dirt = Fill::Block(Block::new(BlockKind::Earth, Rgb::new(161, 116, 86)));

        painter
            .aabb(Aabb {
                min: Vec2::new(center.x - length - 4, center.y - width - 5).with_z(base - 10),
                max: Vec2::new(center.x + length + 9, center.y + width + 8).with_z(base - 1),
            })
            .fill(dirt);

        // air to clear any hills that appear inside of the the barn
        let air = Fill::Block(Block::new(BlockKind::Air, Rgb::new(255, 255, 255)));

        painter
            .aabb(Aabb {
                min: Vec2::new(center.x - length - 4, center.y - width - 5).with_z(base),
                max: Vec2::new(center.x + length + 9, center.y + width + 8).with_z(base + 20),
            })
            .fill(air);

        // Barn prefab
        let barn_path = "site_structures.plot_structures.barn";
        let entrance_pos: Vec3<i32> = (center.x, center.y, self.alt).into();

        let barn_site_pos: Vec3<i32> = entrance_pos + Vec3::new(0, 0, -1);
        render_prefab(barn_path, barn_site_pos, painter);

        // barn animals
        let mut thread_rng = thread_rng();

        let barn_animals = [
            "common.entity.wild.peaceful.cattle",
            "common.entity.wild.peaceful.horse",
        ];

        let desert_barn_animals = [
            "common.entity.wild.peaceful.antelope",
            "common.entity.wild.peaceful.zebra",
            "common.entity.wild.peaceful.camel",
        ];

        for _ in 1..=5 {
            let npc_rng = thread_rng.gen_range(0..=1);
            let desert_npc_rng = thread_rng.gen_range(0..=2);

            let spec = if self.is_desert {
                desert_barn_animals[desert_npc_rng]
            } else {
                barn_animals[npc_rng]
            };

            painter.spawn(
                EntityInfo::at(Vec3::new(center.x, center.y, self.alt).as_()).with_asset_expect(
                    spec,
                    &mut thread_rng,
                    None,
                ),
            );
        }
    }
}