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