veloren_world/site2/plot/
coastal_airship_dock.rs1use super::*;
2use crate::{
3 Land,
4 site2::gen::place_circular,
5 util::{CARDINALS, RandomField, Sampler},
6};
7use common::{
8 generation::SpecialEntity,
9 terrain::{BlockKind, SpriteKind},
10};
11use rand::prelude::*;
12use std::sync::Arc;
13use vek::*;
14
15pub struct CoastalAirshipDock {
17 pub door_tile: Vec2<i32>,
19 pub(crate) alt: i32,
21 base: i32,
22 pub center: Vec2<i32>,
23 size: i32,
24 bldg_height: i32,
25 diameter: i32,
26 pub docking_positions: Vec<Vec3<i32>>,
27}
28
29impl CoastalAirshipDock {
30 pub fn generate(
31 land: &Land,
32 _rng: &mut impl Rng,
33 site: &Site,
34 door_tile: Vec2<i32>,
35 door_dir: Vec2<i32>,
36 tile_aabr: Aabr<i32>,
37 alt: Option<i32>,
38 ) -> Self {
39 let door_tile_pos = site.tile_center_wpos(door_tile);
40 let bounds = Aabr {
41 min: site.tile_wpos(tile_aabr.min),
42 max: site.tile_wpos(tile_aabr.max),
43 };
44 let diameter = (bounds.max.x - bounds.min.x).min(bounds.max.y - bounds.min.y);
45 let alt = alt.unwrap_or_else(|| {
46 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
47 }) + 2;
48 let size = 20;
49 let bldg_height = 12;
50 let base = alt + 1;
51 let center = bounds.center();
52 let mut docking_positions = vec![];
53 let top_floor = base + (bldg_height * 6) - 3;
54 for dir in CARDINALS {
55 let docking_pos = center + dir * (size - 1);
56 docking_positions.push(docking_pos.with_z(top_floor - 1));
57 }
58 Self {
59 door_tile: door_tile_pos,
60 alt,
61 base,
62 center,
63 size,
64 bldg_height,
65 diameter,
66 docking_positions,
67 }
68 }
69
70 pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
71 SpawnRules {
72 trees: {
73 const AIRSHIP_MIN_TREE_DIST2: i32 = 53i32.pow(2);
78 wpos.distance_squared(self.center) > AIRSHIP_MIN_TREE_DIST2
79 },
80 waypoints: false,
81 ..SpawnRules::default()
82 }
83 }
84}
85
86impl Structure for CoastalAirshipDock {
87 #[cfg(feature = "use-dyn-lib")]
88 const UPDATE_FN: &'static [u8] = b"render_coastal_airship_dock\0";
89
90 #[cfg_attr(
91 feature = "be-dyn-lib",
92 unsafe(export_name = "render_coastal_airship_dock")
93 )]
94 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
95 let base = self.base;
96 let center = self.center;
97 let white = Fill::Sampling(Arc::new(|center| {
98 Some(match (RandomField::new(0).get(center)) % 37 {
99 0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
100 9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
101 18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
102 27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
103 _ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
104 })
105 }));
106 let blue_broken = Fill::Sampling(Arc::new(|center| {
107 Some(match (RandomField::new(0).get(center)) % 20 {
108 0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
109 _ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
110 })
111 }));
112
113 let length = self.diameter / 2;
114 let width = (self.diameter / 2) - 1;
115 let height = 15;
116 painter
118 .aabb(Aabb {
119 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
120 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
121 })
122 .fill(blue_broken.clone());
123
124 for dir in CARDINALS {
125 let frame_pos = Vec2::new(
126 center.x + dir.x * (length + 5),
127 center.y + dir.y * (width + 5),
128 );
129 painter
130 .line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
131 .fill(blue_broken.clone());
132 }
133 painter
135 .aabb(Aabb {
136 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
137 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
138 })
139 .fill(white.clone());
140 for f in 0..8 {
141 painter
142 .aabb(Aabb {
143 min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
144 .with_z(base - 3 - f),
145 max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
146 .with_z(base - 2 - f),
147 })
148 .fill(white.clone());
149 }
150 painter
152 .aabb(Aabb {
153 min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
154 max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
155 })
156 .clear();
157 for dir in CARDINALS {
159 let clear_pos = Vec2::new(
160 center.x + dir.x * (length + 7),
161 center.y + dir.y * (width + 7),
162 );
163 painter
164 .line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
165 .clear();
166 }
167
168 let size = self.size;
170 let room_offset = size / 6;
171 let bldg_height = self.bldg_height;
172 for r in 0..=4 {
173 let bldg_size = size - (room_offset * r);
174 let bldg_base = base + ((bldg_height + 2) * r);
175 if r == 4 {
176 painter
177 .cylinder(Aabb {
178 min: (center - bldg_size - 2).with_z(bldg_base + bldg_height - 1),
179 max: (center + bldg_size + 2).with_z(bldg_base + bldg_height),
180 })
181 .fill(white.clone());
182 painter
183 .cylinder(Aabb {
184 min: (center - bldg_size - 2).with_z(bldg_base + bldg_height),
185 max: (center + bldg_size + 2).with_z(bldg_base + bldg_height + 1),
186 })
187 .fill(blue_broken.clone());
188 painter
189 .cylinder(Aabb {
190 min: (center - bldg_size - 1).with_z(bldg_base + bldg_height),
191 max: (center + bldg_size + 1).with_z(bldg_base + bldg_height + 1),
192 })
193 .clear();
194
195 let cargo_pos = Vec2::new(center.x, center.y + 5);
196 for dir in CARDINALS {
197 let sprite_pos = cargo_pos + dir;
198 let rows = 1 + (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
199 for r in 0..rows {
200 painter
201 .aabb(Aabb {
202 min: (sprite_pos).with_z(bldg_base + bldg_height + r),
203 max: (sprite_pos + 1).with_z(bldg_base + bldg_height + 1 + r),
204 })
205 .fill(Fill::Block(Block::air(
206 match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2)
207 as i32
208 {
209 0 => SpriteKind::Barrel,
210 _ => SpriteKind::CrateBlock,
211 },
212 )));
213 if r > 1 {
214 painter.owned_resource_sprite(
215 sprite_pos.with_z(bldg_base + bldg_height + 1 + r),
216 SpriteKind::Crate,
217 0,
218 );
219 }
220 }
221
222 let gangway_pos = center + dir * (size / 2);
224 let dock_pos = center + dir * (size - 4);
225 painter
226 .aabb(Aabb {
227 min: (gangway_pos - 3).with_z(bldg_base + bldg_height - 1),
228 max: (gangway_pos + 3).with_z(bldg_base + bldg_height),
229 })
230 .fill(white.clone());
231 painter
232 .cylinder(Aabb {
233 min: (dock_pos - 4).with_z(bldg_base + bldg_height),
234 max: (dock_pos + 4).with_z(bldg_base + bldg_height + 1),
235 })
236 .fill(blue_broken.clone());
237 painter
238 .cylinder(Aabb {
239 min: (dock_pos - 3).with_z(bldg_base + bldg_height - 1),
240 max: (dock_pos + 3).with_z(bldg_base + bldg_height + 1),
241 })
242 .fill(white.clone());
243 }
244 let campfire_pos = center.with_z(bldg_base + bldg_height);
246 painter.spawn(
247 EntityInfo::at(campfire_pos.map(|e| e as f32 + 0.5))
248 .into_special(SpecialEntity::Waypoint),
249 );
250 }
251 painter
252 .cylinder(Aabb {
253 min: (center - bldg_size).with_z(bldg_base - 2),
254 max: (center + bldg_size).with_z(bldg_base + bldg_height),
255 })
256 .fill(white.clone());
257 }
258 for r in 0..=4 {
259 let bldg_size = size - (room_offset * r);
260 let bldg_base = base + ((bldg_height + 2) * r);
261
262 let step_positions = place_circular(center, (bldg_size - 1) as f32, 14);
263 for (s, step_pos) in step_positions.enumerate() {
264 let step_size = (size / 3) - r;
265
266 painter
267 .cylinder(Aabb {
268 min: (step_pos - step_size).with_z(bldg_base - 2 + s as i32),
269 max: (step_pos + step_size).with_z(bldg_base + 4 + s as i32),
270 })
271 .clear();
272 painter
273 .cylinder(Aabb {
274 min: (step_pos - step_size).with_z(bldg_base - 3 + s as i32),
275 max: (step_pos + step_size).with_z(bldg_base - 2 + s as i32),
276 })
277 .fill(blue_broken.clone());
278 painter
279 .cylinder(Aabb {
280 min: (step_pos - step_size + 1).with_z(bldg_base - 4 + s as i32),
281 max: (step_pos + step_size - 1).with_z(bldg_base - 2 + s as i32),
282 })
283 .fill(white.clone());
284 }
285 let lamp_positions = place_circular(center, (bldg_size + 1) as f32, 14);
286 for (l, lamp_pos) in lamp_positions.enumerate() {
287 if (RandomField::new(0).get(lamp_pos.with_z(base)) % 4) < 1 {
288 painter
289 .aabb(Aabb {
290 min: (lamp_pos - 1).with_z(bldg_base - 3 + l as i32),
291 max: (lamp_pos + 1).with_z(bldg_base - 2 + l as i32),
292 })
293 .fill(blue_broken.clone());
294
295 painter.sprite(
296 lamp_pos.with_z(bldg_base - 2 + l as i32),
297 SpriteKind::FireBowlGround,
298 );
299 }
300 }
301 }
302 }
303}