veloren_world/site2/plot/
workshop.rs1use super::*;
2use crate::{
3 Land,
4 util::{RandomField, Sampler},
5};
6use common::{
7 generation::{EntityInfo, SpecialEntity},
8 terrain::{Block, BlockKind, SpriteKind},
9};
10use rand::prelude::*;
11use vek::*;
12
13pub struct Workshop {
15 bounds: Aabr<i32>,
17 pub(crate) alt: i32,
19}
20
21impl Workshop {
22 pub fn generate(
23 land: &Land,
24 _rng: &mut impl Rng,
25 site: &Site,
26 door_tile: Vec2<i32>,
27 door_dir: Vec2<i32>,
28 tile_aabr: Aabr<i32>,
29 ) -> Self {
30 let bounds = Aabr {
31 min: site.tile_wpos(tile_aabr.min),
32 max: site.tile_wpos(tile_aabr.max),
33 };
34
35 Self {
36 bounds,
37 alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32,
38 }
39 }
40}
41
42impl Structure for Workshop {
43 #[cfg(feature = "use-dyn-lib")]
44 const UPDATE_FN: &'static [u8] = b"render_workshop\0";
45
46 #[cfg_attr(feature = "be-dyn-lib", export_name = "render_workshop")]
47 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
48 let brick = Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24);
49
50 let base = self.alt + 1;
51 let center = self.bounds.center();
52
53 painter
55 .aabb(Aabb {
56 min: (self.bounds.min + 1).with_z(base - 16),
57 max: self.bounds.max.with_z(base),
58 })
59 .fill(brick.clone());
60
61 let roof = base + 5;
62
63 painter
64 .aabb(Aabb {
65 min: (self.bounds.min + 2).with_z(base),
66 max: (self.bounds.max - 1).with_z(roof),
67 })
68 .clear();
69
70 for pos in [
72 Vec2::new(self.bounds.min.x + 3, self.bounds.min.y + 3),
73 Vec2::new(self.bounds.max.x - 3, self.bounds.min.y + 3),
74 Vec2::new(self.bounds.min.x + 3, self.bounds.max.y - 3),
75 Vec2::new(self.bounds.max.x - 3, self.bounds.max.y - 3),
76 ] {
77 painter
78 .line(pos.with_z(base), pos.with_z(roof), 1.0)
79 .fill(Fill::Block(Block::new(
80 BlockKind::Wood,
81 Rgb::new(55, 25, 8),
82 )));
83 }
84
85 let roof_top = roof + 5;
86
87 painter
89 .pyramid(Aabb {
90 min: (self.bounds.min + 2).with_z(roof),
91 max: (self.bounds.max - 1).with_z(roof_top),
92 })
93 .fill(Fill::Brick(BlockKind::Rock, Rgb::new(45, 28, 21), 24));
94
95 let chimney = roof_top + 2;
96
97 let chimney_radius = 3.0;
99 painter
100 .line(
101 center.with_z(base + 4),
102 center.with_z(chimney),
103 chimney_radius,
104 )
105 .fill(brick);
106 painter
107 .line(
108 center.with_z(base),
109 center.with_z(chimney + 2),
110 chimney_radius - 1.0,
111 )
112 .clear();
113 for x in -1..2 {
114 for y in -1..2 {
115 painter.sprite(
116 (center + Vec2::new(x, y)).with_z(base - 1),
117 SpriteKind::Ember,
118 );
119 }
120 }
121 let mut stations = vec![
122 SpriteKind::CraftingBench,
123 SpriteKind::Forge,
124 SpriteKind::SpinningWheel,
125 SpriteKind::TanningRack,
126 SpriteKind::CookingPot,
127 SpriteKind::Cauldron,
128 SpriteKind::Loom,
129 SpriteKind::Anvil,
130 SpriteKind::DismantlingBench,
131 SpriteKind::RepairBench,
132 ];
133 'outer: for d in 0..3 {
134 for dir in CARDINALS {
135 if stations.is_empty() {
136 break 'outer;
137 }
138 let position = center + dir * (3 + d * 2);
139 let cr_station = stations.swap_remove(
140 RandomField::new(0).get(position.with_z(base)) as usize % stations.len(),
141 );
142 painter.sprite(position.with_z(base), cr_station);
143 }
144 }
145
146 painter.spawn(
147 EntityInfo::at(self.bounds.center().with_z(base).map(|e| e as f32 + 0.5))
148 .into_special(SpecialEntity::Waypoint),
149 );
150 }
151}