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(feature = "be-dyn-lib", export_name = "render_coastal_airship_dock")]
91 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
92 let base = self.base;
93 let center = self.center;
94 let white = Fill::Sampling(Arc::new(|center| {
95 Some(match (RandomField::new(0).get(center)) % 37 {
96 0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
97 9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
98 18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
99 27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
100 _ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
101 })
102 }));
103 let blue_broken = Fill::Sampling(Arc::new(|center| {
104 Some(match (RandomField::new(0).get(center)) % 20 {
105 0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
106 _ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
107 })
108 }));
109
110 let length = self.diameter / 2;
111 let width = (self.diameter / 2) - 1;
112 let height = 15;
113 painter
115 .aabb(Aabb {
116 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
117 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
118 })
119 .fill(blue_broken.clone());
120
121 for dir in CARDINALS {
122 let frame_pos = Vec2::new(
123 center.x + dir.x * (length + 5),
124 center.y + dir.y * (width + 5),
125 );
126 painter
127 .line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
128 .fill(blue_broken.clone());
129 }
130 painter
132 .aabb(Aabb {
133 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
134 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
135 })
136 .fill(white.clone());
137 for f in 0..8 {
138 painter
139 .aabb(Aabb {
140 min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
141 .with_z(base - 3 - f),
142 max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
143 .with_z(base - 2 - f),
144 })
145 .fill(white.clone());
146 }
147 painter
149 .aabb(Aabb {
150 min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
151 max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
152 })
153 .clear();
154 for dir in CARDINALS {
156 let clear_pos = Vec2::new(
157 center.x + dir.x * (length + 7),
158 center.y + dir.y * (width + 7),
159 );
160 painter
161 .line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
162 .clear();
163 }
164
165 let size = self.size;
167 let room_offset = size / 6;
168 let bldg_height = self.bldg_height;
169 for r in 0..=4 {
170 let bldg_size = size - (room_offset * r);
171 let bldg_base = base + ((bldg_height + 2) * r);
172 if r == 4 {
173 painter
174 .cylinder(Aabb {
175 min: (center - bldg_size - 2).with_z(bldg_base + bldg_height - 1),
176 max: (center + bldg_size + 2).with_z(bldg_base + bldg_height),
177 })
178 .fill(white.clone());
179 painter
180 .cylinder(Aabb {
181 min: (center - bldg_size - 2).with_z(bldg_base + bldg_height),
182 max: (center + bldg_size + 2).with_z(bldg_base + bldg_height + 1),
183 })
184 .fill(blue_broken.clone());
185 painter
186 .cylinder(Aabb {
187 min: (center - bldg_size - 1).with_z(bldg_base + bldg_height),
188 max: (center + bldg_size + 1).with_z(bldg_base + bldg_height + 1),
189 })
190 .clear();
191
192 let cargo_pos = Vec2::new(center.x, center.y + 5);
193 for dir in CARDINALS {
194 let sprite_pos = cargo_pos + dir;
195 let rows = 1 + (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
196 for r in 0..rows {
197 painter
198 .aabb(Aabb {
199 min: (sprite_pos).with_z(bldg_base + bldg_height + r),
200 max: (sprite_pos + 1).with_z(bldg_base + bldg_height + 1 + r),
201 })
202 .fill(Fill::Block(Block::air(
203 match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2)
204 as i32
205 {
206 0 => SpriteKind::Barrel,
207 _ => SpriteKind::CrateBlock,
208 },
209 )));
210 if r > 1 {
211 painter.owned_resource_sprite(
212 sprite_pos.with_z(bldg_base + bldg_height + 1 + r),
213 SpriteKind::Crate,
214 0,
215 );
216 }
217 }
218
219 let gangway_pos = center + dir * (size / 2);
221 let dock_pos = center + dir * (size - 4);
222 painter
223 .aabb(Aabb {
224 min: (gangway_pos - 3).with_z(bldg_base + bldg_height - 1),
225 max: (gangway_pos + 3).with_z(bldg_base + bldg_height),
226 })
227 .fill(white.clone());
228 painter
229 .cylinder(Aabb {
230 min: (dock_pos - 4).with_z(bldg_base + bldg_height),
231 max: (dock_pos + 4).with_z(bldg_base + bldg_height + 1),
232 })
233 .fill(blue_broken.clone());
234 painter
235 .cylinder(Aabb {
236 min: (dock_pos - 3).with_z(bldg_base + bldg_height - 1),
237 max: (dock_pos + 3).with_z(bldg_base + bldg_height + 1),
238 })
239 .fill(white.clone());
240 }
241 let campfire_pos = center.with_z(bldg_base + bldg_height);
243 painter.spawn(
244 EntityInfo::at(campfire_pos.map(|e| e as f32 + 0.5))
245 .into_special(SpecialEntity::Waypoint),
246 );
247 }
248 painter
249 .cylinder(Aabb {
250 min: (center - bldg_size).with_z(bldg_base - 2),
251 max: (center + bldg_size).with_z(bldg_base + bldg_height),
252 })
253 .fill(white.clone());
254 }
255 for r in 0..=4 {
256 let bldg_size = size - (room_offset * r);
257 let bldg_base = base + ((bldg_height + 2) * r);
258
259 let step_positions = place_circular(center, (bldg_size - 1) as f32, 14);
260 for (s, step_pos) in step_positions.enumerate() {
261 let step_size = (size / 3) - r;
262
263 painter
264 .cylinder(Aabb {
265 min: (step_pos - step_size).with_z(bldg_base - 2 + s as i32),
266 max: (step_pos + step_size).with_z(bldg_base + 4 + s as i32),
267 })
268 .clear();
269 painter
270 .cylinder(Aabb {
271 min: (step_pos - step_size).with_z(bldg_base - 3 + s as i32),
272 max: (step_pos + step_size).with_z(bldg_base - 2 + s as i32),
273 })
274 .fill(blue_broken.clone());
275 painter
276 .cylinder(Aabb {
277 min: (step_pos - step_size + 1).with_z(bldg_base - 4 + s as i32),
278 max: (step_pos + step_size - 1).with_z(bldg_base - 2 + s as i32),
279 })
280 .fill(white.clone());
281 }
282 let lamp_positions = place_circular(center, (bldg_size + 1) as f32, 14);
283 for (l, lamp_pos) in lamp_positions.enumerate() {
284 if (RandomField::new(0).get(lamp_pos.with_z(base)) % 4) < 1 {
285 painter
286 .aabb(Aabb {
287 min: (lamp_pos - 1).with_z(bldg_base - 3 + l as i32),
288 max: (lamp_pos + 1).with_z(bldg_base - 2 + l as i32),
289 })
290 .fill(blue_broken.clone());
291
292 painter.sprite(
293 lamp_pos.with_z(bldg_base - 2 + l as i32),
294 SpriteKind::FireBowlGround,
295 );
296 }
297 }
298 }
299 }
300}