veloren_world/site/plot/
desert_city_airship_dock.rs

1use super::*;
2use crate::{
3    Land,
4    util::{DIAGONALS, RandomField, Sampler, within_distance},
5};
6use common::{
7    generation::SpecialEntity,
8    terrain::{BlockKind, SpriteKind},
9};
10
11use rand::prelude::*;
12use std::sync::Arc;
13use vek::*;
14
15/// Represents house data generated by the `generate()` method
16pub struct DesertCityAirshipDock {
17    /// Tile position of the door tile
18    pub door_tile: Vec2<i32>,
19    /// Axis aligned bounding region for the house
20    bounds: Aabr<i32>,
21    /// Approximate altitude of the door tile
22    pub(crate) alt: i32,
23    pub docking_positions: Vec<Vec3<i32>>,
24    pub center: Vec2<i32>,
25    base: i32,
26    length: i32,
27    height: i32,
28    floors: i32,
29}
30
31impl DesertCityAirshipDock {
32    pub fn generate(
33        land: &Land,
34        _rng: &mut impl Rng,
35        site: &Site,
36        door_tile: Vec2<i32>,
37        door_dir: Vec2<i32>,
38        tile_aabr: Aabr<i32>,
39        alt: Option<i32>,
40    ) -> Self {
41        let door_tile_pos = site.tile_center_wpos(door_tile);
42        let bounds = Aabr {
43            min: site.tile_wpos(tile_aabr.min),
44            max: site.tile_wpos(tile_aabr.max),
45        };
46        let alt = alt.unwrap_or_else(|| {
47            land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
48        });
49        let center = bounds.center();
50        let length = 14;
51        let height = 2 * (length / 3);
52        let floors = 4;
53        let base = alt + 1;
54        let top_floor = base + 5 + (height * (floors + 1));
55        let docking_positions = CARDINALS
56            .iter()
57            .map(|dir| (center + dir * 31).with_z(top_floor))
58            .collect::<Vec<_>>();
59        Self {
60            bounds,
61            door_tile: door_tile_pos,
62            alt,
63            docking_positions,
64            center,
65            base,
66            length,
67            height,
68            floors,
69        }
70    }
71
72    pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
73        SpawnRules {
74            trees: {
75                // dock is 5 tiles = 30 blocks in radius
76                // airships are 39 blocks wide.
77                // Tree can be up to 20 blocks in radius.
78                // Don't allow trees within 30 + 39 + 20 = 89 blocks of the dock center
79                const AIRSHIP_MIN_TREE_DIST: i32 = 89;
80                !within_distance(wpos, self.center, AIRSHIP_MIN_TREE_DIST)
81            },
82            waypoints: false,
83            ..SpawnRules::default()
84        }
85    }
86}
87
88impl Structure for DesertCityAirshipDock {
89    #[cfg(feature = "use-dyn-lib")]
90    const UPDATE_FN: &'static [u8] = b"render_desertcityairshipdock\0";
91
92    #[cfg_attr(
93        feature = "be-dyn-lib",
94        unsafe(export_name = "render_desertcityairshipdock")
95    )]
96    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
97        let sandstone = Fill::Sampling(Arc::new(|center| {
98            Some(match (RandomField::new(0).get(center)) % 37 {
99                0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
100                9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
101                18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
102                27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
103                _ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
104            })
105        }));
106        let sandstone_broken = Fill::Sampling(Arc::new(|center| {
107            Some(match (RandomField::new(0).get(center)) % 42 {
108                0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
109                9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
110                18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
111                27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
112                36..=40 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
113                _ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
114            })
115        }));
116        let wood = Fill::Brick(BlockKind::Wood, Rgb::new(71, 33, 11), 12);
117        let base = self.base;
118        let center = self.center;
119        // Fence
120        painter
121            .aabb(Aabb {
122                min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
123                max: Vec2::new(self.bounds.min.x + 2, self.bounds.max.y).with_z(base + 2),
124            })
125            .union(painter.aabb(Aabb {
126                min: Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 1).with_z(base - 20),
127                max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
128            }))
129            .union(painter.aabb(Aabb {
130                min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
131                max: Vec2::new(self.bounds.max.x, self.bounds.min.y + 2).with_z(base + 2),
132            }))
133            .union(painter.aabb(Aabb {
134                min: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 1).with_z(base - 20),
135                max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
136            }))
137            .fill(sandstone_broken);
138        painter
139            .aabb(Aabb {
140                min: Vec2::new(self.bounds.min.x + 1, center.y - 8).with_z(base),
141                max: Vec2::new(self.bounds.max.x, center.y + 8).with_z(base + 7),
142            })
143            .clear();
144        painter
145            .aabb(Aabb {
146                min: Vec2::new(center.x - 7, self.bounds.min.y + 1).with_z(base),
147                max: Vec2::new(center.x + 9, self.bounds.max.y).with_z(base + 7),
148            })
149            .clear();
150        // Foundation
151        painter
152            .aabb(Aabb {
153                min: (self.bounds.min + 1).with_z(base - 20),
154                max: (self.bounds.max).with_z(base),
155            })
156            .fill(sandstone.clone());
157
158        // rooms
159        let length = self.length;
160        let height = self.height;
161        let floors = self.floors;
162        let carve = length / 4;
163
164        for f in 0..=floors {
165            let bldg_base = base + f * (height + 1);
166            let bldg_length = length;
167            if f == floors {
168                // Agent Desk
169                painter
170                    .aabb(Aabb {
171                        min: Vec2::new(center.x - 7, center.y - 5).with_z(bldg_base + height),
172                        max: Vec2::new(center.x - 12, center.y + 5).with_z(bldg_base + height + 6),
173                    })
174                    .fill(sandstone.clone());
175                painter
176                    .aabb(Aabb {
177                        min: Vec2::new(center.x - 8, center.y - 4).with_z(bldg_base + height),
178                        max: Vec2::new(center.x - 11, center.y + 4).with_z(bldg_base + height + 5),
179                    })
180                    .clear();
181                painter
182                    .aabb(Aabb {
183                        min: Vec2::new(center.x - 11, center.y - 5).with_z(bldg_base + height),
184                        max: Vec2::new(center.x - 12, center.y + 5).with_z(bldg_base + height + 5),
185                    })
186                    .clear();
187                painter
188                    .aabb(Aabb {
189                        min: Vec2::new(center.x - 10, center.y - 4).with_z(bldg_base + height),
190                        max: Vec2::new(center.x - 11, center.y + 4).with_z(bldg_base + height + 2),
191                    })
192                    .fill(wood.clone());
193            }
194            // room
195            painter
196                .aabb(Aabb {
197                    min: (center - bldg_length).with_z(bldg_base),
198                    max: (center + bldg_length).with_z(bldg_base + height),
199                })
200                .fill(sandstone.clone());
201            // roof floor
202            painter
203                .aabb(Aabb {
204                    min: (center - bldg_length - 1 - f).with_z(bldg_base + height),
205                    max: (center + bldg_length + 1 + f).with_z(bldg_base + height + 1),
206                })
207                .fill(wood.clone());
208            painter
209                .aabb(Aabb {
210                    min: (center - bldg_length - f).with_z(bldg_base + height),
211                    max: (center + bldg_length + f).with_z(bldg_base + height + 1),
212                })
213                .fill(sandstone.clone());
214            // clear room
215            painter
216                .aabb(Aabb {
217                    min: (center - bldg_length + 1).with_z(bldg_base),
218                    max: (center + bldg_length - 1).with_z(bldg_base + height - 1),
219                })
220                .clear();
221
222            let clear_limit_1 = painter.aabb(Aabb {
223                min: Vec2::new(center.x - bldg_length, center.y - bldg_length + 1)
224                    .with_z(bldg_base),
225                max: Vec2::new(center.x + bldg_length, center.y + bldg_length - 1)
226                    .with_z(bldg_base + height),
227            });
228            let clear_limit_2 = painter.aabb(Aabb {
229                min: Vec2::new(center.x - bldg_length + 1, center.y - bldg_length)
230                    .with_z(bldg_base),
231                max: Vec2::new(center.x + bldg_length - 1, center.y + bldg_length)
232                    .with_z(bldg_base + height),
233            });
234            for c in 0..=4 {
235                let space = c * ((2 * carve) + 1);
236                painter
237                    .vault(
238                        Aabb {
239                            min: Vec2::new(
240                                center.x - bldg_length,
241                                center.y + space - bldg_length - carve + 1,
242                            )
243                            .with_z(bldg_base + (height / 2)),
244                            max: Vec2::new(
245                                center.x + bldg_length,
246                                center.y + space - bldg_length + carve - 1,
247                            )
248                            .with_z(bldg_base + height - 1),
249                        },
250                        Dir::X,
251                    )
252                    .intersect(clear_limit_1)
253                    .clear();
254                painter
255                    .vault(
256                        Aabb {
257                            min: Vec2::new(
258                                center.x + space - bldg_length - carve + 1,
259                                center.y - bldg_length,
260                            )
261                            .with_z(bldg_base + (height / 2)),
262                            max: Vec2::new(
263                                center.x + space - bldg_length + carve - 1,
264                                center.y + bldg_length,
265                            )
266                            .with_z(bldg_base + height - 1),
267                        },
268                        Dir::Y,
269                    )
270                    .intersect(clear_limit_2)
271                    .clear();
272
273                painter
274                    .aabb(Aabb {
275                        min: Vec2::new(
276                            center.x - bldg_length,
277                            center.y + space - bldg_length - carve,
278                        )
279                        .with_z(bldg_base),
280                        max: Vec2::new(
281                            center.x + bldg_length,
282                            center.y + space - bldg_length + carve,
283                        )
284                        .with_z(bldg_base + (height / 2)),
285                    })
286                    .intersect(clear_limit_1)
287                    .clear();
288                painter
289                    .aabb(Aabb {
290                        min: Vec2::new(
291                            center.x + space - bldg_length - carve,
292                            center.y - bldg_length,
293                        )
294                        .with_z(bldg_base),
295                        max: Vec2::new(
296                            center.x + space - bldg_length + carve,
297                            center.y + bldg_length,
298                        )
299                        .with_z(bldg_base + (height / 2)),
300                    })
301                    .intersect(clear_limit_2)
302                    .clear();
303            }
304            for dir in DIAGONALS {
305                let clear_pos = center + dir * bldg_length;
306                painter
307                    .aabb(Aabb {
308                        min: (clear_pos - 1).with_z(bldg_base),
309                        max: (clear_pos + 1).with_z(bldg_base + height - 1),
310                    })
311                    .clear();
312            }
313            for dir in DIAGONALS {
314                let lamp_pos = center + dir * (bldg_length - 1);
315                painter.sprite(lamp_pos.with_z(bldg_base), SpriteKind::StreetLamp);
316                if f == 4 {
317                    let lamp_pos = center + dir * bldg_length;
318                    painter.sprite(
319                        lamp_pos.with_z(bldg_base + height + 1),
320                        SpriteKind::StreetLamp,
321                    );
322
323                    let cargo_pos = center + (dir * ((bldg_length / 2) + 1));
324                    for dir in CARDINALS {
325                        let sprite_pos = cargo_pos + dir;
326                        let rows = (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
327                        for r in 0..rows {
328                            painter
329                                .aabb(Aabb {
330                                    min: (sprite_pos).with_z(bldg_base + height + 1 + r),
331                                    max: (sprite_pos + 1).with_z(bldg_base + height + 2 + r),
332                                })
333                                .fill(Fill::Block(Block::air(
334                                    match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2)
335                                        as i32
336                                    {
337                                        0 => SpriteKind::Barrel,
338                                        _ => SpriteKind::CrateBlock,
339                                    },
340                                )));
341                            if r > 0 {
342                                painter.owned_resource_sprite(
343                                    sprite_pos.with_z(bldg_base + height + 2 + r),
344                                    SpriteKind::Crate,
345                                    0,
346                                );
347                            }
348                        }
349                    }
350                }
351            }
352            // docks
353            if f == 4 {
354                for dir in CARDINALS {
355                    let gangway_pos_1 = center + dir * (3 * (bldg_length / 2));
356                    let gangway_pos_2 = center + dir * ((3 * (bldg_length / 2)) - 4);
357                    let dock_pos = center + dir * 27;
358                    painter
359                        .aabb(Aabb {
360                            min: (gangway_pos_2 - 3).with_z(bldg_base + height - 1),
361                            max: (gangway_pos_2 + 3).with_z(bldg_base + height),
362                        })
363                        .fill(wood.clone());
364                    painter
365                        .aabb(Aabb {
366                            min: (gangway_pos_1 - 3).with_z(bldg_base + height),
367                            max: (gangway_pos_1 + 3).with_z(bldg_base + height + 1),
368                        })
369                        .fill(wood.clone());
370                    painter
371                        .cylinder(Aabb {
372                            min: (dock_pos - 4).with_z(bldg_base + height),
373                            max: (dock_pos + 4).with_z(bldg_base + height + 1),
374                        })
375                        .fill(wood.clone());
376                    painter
377                        .cylinder(Aabb {
378                            min: (dock_pos - 3).with_z(bldg_base + height - 1),
379                            max: (dock_pos + 3).with_z(bldg_base + height),
380                        })
381                        .fill(wood.clone());
382                }
383                // campfire
384                painter.spawn(
385                    EntityInfo::at(
386                        Vec2::new(center.x + bldg_length - 2, center.y)
387                            .with_z(bldg_base + height + 1)
388                            .map(|e| e as f32 + 0.5),
389                    )
390                    .into_special(SpecialEntity::Waypoint),
391                );
392            }
393            // stairs
394            painter
395                .aabb(Aabb {
396                    min: (center - (bldg_length / 2) - 1).with_z(bldg_base + height - 1),
397                    max: (center + (bldg_length / 2) + 1).with_z(bldg_base + height + 1),
398                })
399                .fill(wood.clone());
400            painter
401                .aabb(Aabb {
402                    min: (center - (bldg_length / 2)).with_z(bldg_base + height - 1),
403                    max: (center + (bldg_length / 2)).with_z(bldg_base + height + 1),
404                })
405                .clear();
406
407            for w in 0..((bldg_length / 2) + 2) {
408                painter
409                    .aabb(Aabb {
410                        min: Vec2::new(
411                            center.x - (bldg_length / 2) - 2 + (2 * w),
412                            center.y - (bldg_length / 2),
413                        )
414                        .with_z(bldg_base + w),
415                        max: Vec2::new(
416                            center.x - (bldg_length / 2) - 2 + (2 * w) + 2,
417                            center.y + (bldg_length / 2),
418                        )
419                        .with_z(bldg_base + 1 + w),
420                    })
421                    .fill(wood.clone());
422                painter
423                    .aabb(Aabb {
424                        min: Vec2::new(
425                            center.x - (bldg_length / 2) - 2 + (2 * w),
426                            center.y - (bldg_length / 2),
427                        )
428                        .with_z(bldg_base - 1 + w),
429                        max: Vec2::new(
430                            center.x - (bldg_length / 2) - 2 + (2 * w) + 2,
431                            center.y + (bldg_length / 2),
432                        )
433                        .with_z(bldg_base + w),
434                    })
435                    .fill(sandstone.clone());
436            }
437        }
438    }
439}