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