veloren_world/site2/plot/
coastal_workshop.rs

1use super::*;
2use crate::{
3    Land,
4    util::{CARDINALS, RandomField, Sampler},
5};
6use common::{
7    generation::SpecialEntity,
8    terrain::{BlockKind, SpriteKind},
9};
10use rand::prelude::*;
11use std::sync::Arc;
12use vek::*;
13
14/// Represents house data generated by the `generate()` method
15pub struct CoastalWorkshop {
16    /// Tile position of the door tile
17    pub door_tile: Vec2<i32>,
18    /// Axis aligned bounding region for the house
19    bounds: Aabr<i32>,
20    /// Approximate altitude of the door tile
21    pub(crate) alt: i32,
22}
23
24impl CoastalWorkshop {
25    pub fn generate(
26        land: &Land,
27        _rng: &mut impl Rng,
28        site: &Site,
29        door_tile: Vec2<i32>,
30        door_dir: Vec2<i32>,
31        tile_aabr: Aabr<i32>,
32    ) -> Self {
33        let door_tile_pos = site.tile_center_wpos(door_tile);
34        let bounds = Aabr {
35            min: site.tile_wpos(tile_aabr.min),
36            max: site.tile_wpos(tile_aabr.max),
37        };
38        Self {
39            door_tile: door_tile_pos,
40            bounds,
41            alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2,
42        }
43    }
44}
45
46impl Structure for CoastalWorkshop {
47    #[cfg(feature = "use-dyn-lib")]
48    const UPDATE_FN: &'static [u8] = b"render_coastalworkshop\0";
49
50    #[cfg_attr(feature = "be-dyn-lib", export_name = "render_coastalworkshop")]
51    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
52        let base = self.alt + 1;
53        let center = self.bounds.center();
54        let white = Fill::Sampling(Arc::new(|center| {
55            Some(match (RandomField::new(0).get(center)) % 37 {
56                0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
57                9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
58                18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
59                27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
60                _ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
61            })
62        }));
63        let blue_broken = Fill::Sampling(Arc::new(|center| {
64            Some(match (RandomField::new(0).get(center)) % 20 {
65                0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
66                _ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
67            })
68        }));
69        let length = (14 + RandomField::new(0).get(center.with_z(base)) % 3) as i32;
70        let width = (12 + RandomField::new(0).get((center - 1).with_z(base)) % 3) as i32;
71        let height = (12 + RandomField::new(0).get((center + 1).with_z(base)) % 4) as i32;
72
73        // fence, blue gates
74        painter
75            .aabb(Aabb {
76                min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
77                max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
78            })
79            .fill(blue_broken.clone());
80
81        for dir in CARDINALS {
82            let frame_pos = Vec2::new(
83                center.x + dir.x * (length + 5),
84                center.y + dir.y * (width + 5),
85            );
86            painter
87                .line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
88                .fill(blue_broken.clone());
89        }
90        // foundation
91        painter
92            .aabb(Aabb {
93                min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
94                max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
95            })
96            .fill(white.clone());
97        for f in 0..8 {
98            painter
99                .aabb(Aabb {
100                    min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
101                        .with_z(base - 3 - f),
102                    max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
103                        .with_z(base - 2 - f),
104                })
105                .fill(white.clone());
106        }
107        // clear yard
108        painter
109            .aabb(Aabb {
110                min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
111                max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
112            })
113            .clear();
114        // clear entries
115        for dir in CARDINALS {
116            let clear_pos = Vec2::new(
117                center.x + dir.x * (length + 7),
118                center.y + dir.y * (width + 7),
119            );
120            painter
121                .line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
122                .clear();
123        }
124        // roof terrace
125        painter
126            .aabb(Aabb {
127                min: Vec2::new(center.x - length - 3, center.y - width - 3)
128                    .with_z(base - 3 + height),
129                max: Vec2::new(center.x + length + 2, center.y + width + 2)
130                    .with_z(base - 2 + height),
131            })
132            .fill(white.clone());
133        painter
134            .aabb(Aabb {
135                min: Vec2::new(center.x - length - 3, center.y - width - 3)
136                    .with_z(base - 2 + height),
137                max: Vec2::new(center.x + length + 2, center.y + width + 2)
138                    .with_z(base - 1 + height),
139            })
140            .fill(blue_broken.clone());
141        painter
142            .aabb(Aabb {
143                min: Vec2::new(center.x - length - 2, center.y - width - 2)
144                    .with_z(base - 2 + height),
145                max: Vec2::new(center.x + length + 1, center.y + width + 1)
146                    .with_z(base - 1 + height),
147            })
148            .clear();
149        // room
150        painter
151            .aabb(Aabb {
152                min: Vec2::new(center.x - length, center.y - width).with_z(base - 2),
153                max: Vec2::new(center.x + length, center.y + width).with_z(base - 1),
154            })
155            .fill(blue_broken.clone());
156        painter
157            .aabb(Aabb {
158                min: Vec2::new(center.x - length + 1, center.y - width + 1).with_z(base - 2),
159                max: Vec2::new(center.x + length - 1, center.y + width - 1)
160                    .with_z(base - 1 + height - 1),
161            })
162            .fill(white.clone());
163
164        // entries
165        let entry_limit = painter.aabb(Aabb {
166            min: Vec2::new(center.x - length, center.y - width).with_z(base - 2),
167            max: Vec2::new(center.x + length, center.y + width).with_z(base - 1 + height - 1),
168        });
169        painter
170            .line(
171                Vec2::new(center.x, center.y + 1 - width).with_z(base - 1),
172                Vec2::new(center.x, center.y - 2 + width).with_z(base - 1),
173                8.0,
174            )
175            .intersect(entry_limit)
176            .fill(blue_broken.clone());
177        painter
178            .line(
179                Vec2::new(center.x, center.y - width).with_z(base - 1),
180                Vec2::new(center.x, center.y + width).with_z(base - 1),
181                7.0,
182            )
183            .intersect(entry_limit)
184            .clear();
185        painter
186            .line(
187                Vec2::new(center.x + 1 - length, center.y).with_z(base - 1),
188                Vec2::new(center.x - 2 + length, center.y).with_z(base - 1),
189                8.0,
190            )
191            .intersect(entry_limit)
192            .fill(blue_broken.clone());
193        painter
194            .line(
195                Vec2::new(center.x - length, center.y).with_z(base - 1),
196                Vec2::new(center.x + length, center.y).with_z(base - 1),
197                7.0,
198            )
199            .intersect(entry_limit)
200            .clear();
201        // clear room
202        painter
203            .aabb(Aabb {
204                min: Vec2::new(center.x - length + 2, center.y - width + 2).with_z(base - 2),
205                max: Vec2::new(center.x + length - 2, center.y + width - 2)
206                    .with_z(base - 2 + height - 1),
207            })
208            .clear();
209
210        // room floors
211        painter
212            .aabb(Aabb {
213                min: Vec2::new(center.x - length + 5, center.y - width + 5).with_z(base - 3),
214                max: Vec2::new(center.x + length - 5, center.y + width - 5).with_z(base - 2),
215            })
216            .fill(blue_broken.clone());
217        painter
218            .aabb(Aabb {
219                min: Vec2::new(center.x - length + 6, center.y - width + 6).with_z(base - 3),
220                max: Vec2::new(center.x + length - 6, center.y + width - 6).with_z(base - 2),
221            })
222            .fill(white.clone());
223
224        // wall lamps
225        for d in 0..2 {
226            let door_lamp_pos =
227                Vec2::new(center.x - length + 2 + (d * ((2 * (length)) - 5)), center.y)
228                    .with_z(base + 6);
229            painter.rotated_sprite(
230                door_lamp_pos,
231                SpriteKind::WallLampSmall,
232                2 + ((d * 4) as u8),
233            );
234
235            let lamp_pos = Vec2::new(center.x, center.y - width + 2 + (d * ((2 * (width)) - 5)))
236                .with_z(base + 6);
237            painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 4 - ((d * 4) as u8));
238        }
239        for d in 0..2 {
240            let door_lamp_pos =
241                Vec2::new(center.x - length - 1 + (d * ((2 * (length)) + 1)), center.y)
242                    .with_z(base + 6);
243            painter.rotated_sprite(
244                door_lamp_pos,
245                SpriteKind::WallLampSmall,
246                6 + ((d * 4) as u8),
247            );
248
249            let lamp_pos = Vec2::new(center.x, center.y - width - 1 + (d * ((2 * (width)) + 1)))
250                .with_z(base + 6);
251            painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 8 - ((d * 4) as u8));
252        }
253
254        // chimney
255        painter
256            .cylinder(Aabb {
257                min: (center - 4).with_z(base + height - 4),
258                max: (center + 2).with_z(base - 2 + height + (height / 2)),
259            })
260            .fill(blue_broken);
261
262        let top_limit = painter.aabb(Aabb {
263            min: Vec2::new(center.x - length, center.y - width).with_z(base + height - 2),
264            max: Vec2::new(center.x + length, center.y + width)
265                .with_z(base - 2 + height + (height / 2)),
266        });
267        painter
268            .superquadric(
269                Aabb {
270                    min: Vec2::new(center.x - length - 1, center.y - width - 1)
271                        .with_z(base + height - (height / 2)),
272                    max: Vec2::new(center.x + length, center.y + width)
273                        .with_z(base - 2 + height + (height / 2)),
274                },
275                1.5,
276            )
277            .intersect(top_limit)
278            .fill(white.clone());
279        // clear chimney
280        painter
281            .cylinder(Aabb {
282                min: (center - 3).with_z(base + height - 4),
283                max: (center + 1).with_z(base - 2 + height + (height / 2)),
284            })
285            .clear();
286
287        painter
288            .cylinder(Aabb {
289                min: (center - 3).with_z(base - 2),
290                max: (center + 1).with_z(base - 1),
291            })
292            .fill(white);
293        painter
294            .aabb(Aabb {
295                min: (center - 2).with_z(base - 2),
296                max: (center).with_z(base - 1),
297            })
298            .clear();
299        painter
300            .aabb(Aabb {
301                min: (center - 2).with_z(base - 3),
302                max: (center).with_z(base - 2),
303            })
304            .fill(Fill::Block(Block::air(SpriteKind::Ember)));
305
306        let mut stations = vec![
307            SpriteKind::CraftingBench,
308            SpriteKind::Forge,
309            SpriteKind::SpinningWheel,
310            SpriteKind::TanningRack,
311            SpriteKind::CookingPot,
312            SpriteKind::Cauldron,
313            SpriteKind::Loom,
314            SpriteKind::Anvil,
315            SpriteKind::DismantlingBench,
316            SpriteKind::RepairBench,
317        ];
318        'outer: for d in 0..3 {
319            for dir in CARDINALS {
320                if stations.is_empty() {
321                    break 'outer;
322                }
323                let position = center + dir * (4 + d * 2);
324                let cr_station = stations.swap_remove(
325                    RandomField::new(0).get(position.with_z(base)) as usize % stations.len(),
326                );
327                painter.sprite(position.with_z(base - 2), cr_station);
328            }
329        }
330
331        painter.spawn(
332            EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5))
333                .into_special(SpecialEntity::Waypoint),
334        );
335    }
336}