veloren_world/site2/plot/
airship_dock.rs

1use super::*;
2use crate::{
3    Land,
4    site2::gen::{PrimitiveTransform, spiral_staircase},
5    util::{CARDINALS, DIAGONALS, RandomField, Sampler},
6};
7use common::{
8    generation::SpecialEntity,
9    terrain::{BlockKind, SpriteKind},
10};
11use rand::prelude::*;
12use std::f32::consts::PI;
13use vek::*;
14/// Represents house data generated by the `generate()` method
15pub struct AirshipDock {
16    /// Approximate altitude of the door tile
17    pub(crate) alt: i32,
18    rotation: f32,
19    pub door_tile: Vec2<i32>,
20    pub center: Vec2<i32>,
21    base: i32,
22    height: i32,
23    pub docking_positions: Vec<Vec3<i32>>,
24    pub door_dir: Vec2<i32>,
25    campfire_pos: Vec3<i32>,
26}
27
28impl AirshipDock {
29    pub fn generate(
30        land: &Land,
31        _rng: &mut impl Rng,
32        site: &Site,
33        door_tile: Vec2<i32>,
34        door_dir: Vec2<i32>,
35        tile_aabr: Aabr<i32>,
36        alt: Option<i32>,
37    ) -> Self {
38        let door_tile_pos: Vec2<i32> = site.tile_center_wpos(door_tile);
39        let bounds = Aabr {
40            min: site.tile_wpos(tile_aabr.min),
41            max: site.tile_wpos(tile_aabr.max),
42        };
43        let center = bounds.center();
44        let alt = alt.unwrap_or_else(|| {
45            land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
46        });
47        let base = alt + 3;
48        let height = base + 28;
49        let rotation = if door_dir.y < 0 {
50            PI
51        } else if door_dir.x < 0 {
52            PI / 2.0
53        } else if door_dir.y > 0 {
54            3.0 * PI / 2.0
55        } else {
56            0.0
57        };
58        let mut docking_positions = vec![];
59        for dir in CARDINALS {
60            let pos = (center + dir * 19).with_z(height + 9);
61            docking_positions.push(pos);
62        }
63        let campfire_pos = (center - (door_dir * 10)).with_z(height + 9);
64        Self {
65            door_tile: door_tile_pos,
66            alt,
67            rotation,
68            center,
69            base,
70            height,
71            docking_positions,
72            door_dir,
73            campfire_pos,
74        }
75    }
76
77    pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
78        SpawnRules {
79            trees: {
80                // dock is 3 tiles = 18 blocks in radius
81                // airships are 20 blocks wide.
82                // Some trees are 20 to 30 blocks in radius.
83                // Leave extra space for tree width.
84                // Don't allow trees within 18 + 20 + 30 = 68 blocks of the dock center
85                const AIRSHIP_MIN_TREE_DIST2: i32 = 68i32.pow(2);
86                wpos.distance_squared(self.center) > AIRSHIP_MIN_TREE_DIST2
87            },
88            waypoints: false,
89            ..SpawnRules::default()
90        }
91    }
92}
93
94impl Structure for AirshipDock {
95    #[cfg(feature = "use-dyn-lib")]
96    const UPDATE_FN: &'static [u8] = b"render_airshipdock\0";
97
98    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_airshipdock"))]
99    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
100        let brick = Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24);
101        let wood = Fill::Brick(BlockKind::Rock, Rgb::new(45, 28, 21), 24);
102        let woodalt = Fill::Brick(BlockKind::Rock, Rgb::new(30, 22, 15), 24);
103
104        let base = self.base;
105        let center = self.center;
106        let height = self.height;
107
108        //lower doorway
109        painter
110            .cylinder_with_radius(
111                Vec2::new(center.x - 1, center.y + 12).with_z(base - 5),
112                4.5,
113                7.0,
114            )
115            .rotate_about_min(Mat3::new(1, 0, 0, 0, 0, -1, 0, 1, 0))
116            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
117            .fill(wood.clone());
118
119        //bracing
120        painter
121            .cylinder_with_radius(center.with_z(height), 7.0, 7.0)
122            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
123            .fill(wood.clone());
124        painter
125            .cylinder_with_radius(center.with_z(height + 1), 7.0, 5.0)
126            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
127            .clear();
128        painter
129            .cylinder_with_radius(center.with_z(height + 7), 8.0, 1.0)
130            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
131            .fill(wood.clone());
132
133        //platform edging
134        painter
135            .superquadric(
136                Aabb {
137                    min: (center - 17).with_z(base + 35),
138                    max: (center + 17).with_z(height + 11),
139                },
140                5.0,
141            )
142            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
143            .fill(woodalt.clone());
144        //platform
145        painter
146            .superquadric(
147                Aabb {
148                    min: (center - 16).with_z(base + 36),
149                    max: (center + 16).with_z(height + 11),
150                },
151                5.0,
152            )
153            .fill(wood.clone());
154        painter
155            .superquadric(
156                Aabb {
157                    min: (center - 16).with_z(base + 37),
158                    max: (center + 16).with_z(height + 12),
159                },
160                5.0,
161            )
162            .clear();
163        //column
164        painter
165            .cylinder_with_radius(center.with_z(base), 6.0, 45.0)
166            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
167            .fill(brick.clone());
168        //column thick bits
169        painter
170            .cylinder_with_radius(center.with_z(base + 35), 7.0, 3.0)
171            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
172            .fill(brick.clone());
173        painter
174            .cylinder_with_radius(center.with_z(base), 7.0, 1.0)
175            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
176            .fill(brick.clone());
177
178        painter
179            .cylinder_with_radius(center.with_z(base), 5.0, 45.0)
180            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
181            .clear();
182        //lower doorway cut
183        painter
184            .cylinder_with_radius(
185                Vec2::new(center.x - 1, center.y + 12).with_z(base - 5),
186                3.5,
187                7.0,
188            )
189            .rotate_about_min(Mat3::new(1, 0, 0, 0, 0, -1, 0, 1, 0))
190            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
191            .clear();
192        // Base
193        painter
194            .aabb(Aabb {
195                min: Vec2::new(center.x - 11, center.y - 11).with_z(base - 16),
196                max: Vec2::new(center.x + 11, center.y + 11).with_z(base),
197            })
198            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
199            .fill(brick.clone());
200
201        //stair cut
202        painter
203            .aabb(Aabb {
204                min: Vec2::new(center.x - 6, center.y + 9).with_z(base - 1),
205                max: Vec2::new(center.x + 4, center.y + 11).with_z(base),
206            })
207            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
208            .clear();
209        painter
210            .aabb(Aabb {
211                min: Vec2::new(center.x - 5, center.y + 10).with_z(base - 2),
212                max: Vec2::new(center.x + 3, center.y + 11).with_z(base - 1),
213            })
214            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
215            .clear();
216        //cone
217        painter
218            .cone_with_radius(center.with_z(base + 45), 8.0, 18.0)
219            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
220            .fill(wood.clone());
221        //remove 1/4 cyl
222        painter
223            .aabb(Aabb {
224                min: Vec2::new(center.x - 1, center.y + 1).with_z(height + 9),
225                max: Vec2::new(center.x + 6, center.y + 6).with_z(height + 17),
226            })
227            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
228            .fill(brick.clone());
229        painter
230            .aabb(Aabb {
231                min: Vec2::new(center.x, center.y + 2).with_z(height + 9),
232                max: Vec2::new(center.x + 6, center.y + 7).with_z(height + 17),
233            })
234            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
235            .clear();
236        //platform cleanup
237        painter
238            .aabb(Aabb {
239                min: Vec2::new(center.x - 2, center.y - 15).with_z(height + 8),
240                max: Vec2::new(center.x + 6, center.y + 9).with_z(height + 9),
241            })
242            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
243            .fill(wood.clone());
244
245        //upper door
246        painter
247            .aabb(Aabb {
248                min: Vec2::new(center.x + 5, center.y - 2).with_z(height + 10),
249                max: Vec2::new(center.x + 7, center.y + 2).with_z(height + 13),
250            })
251            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
252            .fill(brick.clone());
253        painter
254            .aabb(Aabb {
255                min: Vec2::new(center.x + 5, center.y - 1).with_z(height + 10),
256                max: Vec2::new(center.x + 7, center.y + 1).with_z(height + 15),
257            })
258            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
259            .fill(brick.clone());
260        painter
261            .aabb(Aabb {
262                min: Vec2::new(center.x + 5, center.y - 1).with_z(height + 10),
263                max: Vec2::new(center.x + 7, center.y + 1).with_z(height + 13),
264            })
265            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
266            .clear();
267        //door sprites
268
269        let door_rot = if self.rotation == 0.0 {
270            (2, 6)
271        } else if self.rotation == PI / 2.0 {
272            (4, 0)
273        } else if self.rotation == PI {
274            (6, 2) //good
275        } else {
276            (0, 4)
277        };
278        let sprite_fill = Fill::Block(Block::air(SpriteKind::Door).with_ori(door_rot.0).unwrap());
279        painter
280            .aabb(Aabb {
281                min: Vec3::new(center.x + 6, center.y - 1, height + 10),
282                max: Vec3::new(center.x + 7, center.y + 0, height + 11),
283            })
284            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
285            .fill(sprite_fill.clone());
286        let sprite_fill = Fill::Block(Block::air(SpriteKind::Door).with_ori(door_rot.1).unwrap());
287        painter
288            .aabb(Aabb {
289                min: Vec3::new(center.x + 6, center.y + 0, height + 10),
290                max: Vec3::new(center.x + 7, center.y + 1, height + 11),
291            })
292            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
293            .fill(sprite_fill.clone());
294
295        //bracing diagonal bits
296        painter
297            .line(
298                Vec2::new(center.x + 5, center.y - 3).with_z(height),
299                Vec2::new(center.x + 11, center.y - 3).with_z(height + 8),
300                0.8,
301            )
302            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
303            .fill(wood.clone());
304        painter
305            .line(
306                Vec2::new(center.x + 5, center.y + 2).with_z(height),
307                Vec2::new(center.x + 11, center.y + 2).with_z(height + 8),
308                0.8,
309            )
310            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
311            .fill(wood.clone());
312        //
313        painter
314            .line(
315                Vec2::new(center.x - 11, center.y - 3).with_z(height + 8),
316                Vec2::new(center.x - 6, center.y - 3).with_z(height),
317                0.8,
318            )
319            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
320            .fill(wood.clone());
321        painter
322            .line(
323                Vec2::new(center.x - 11, center.y + 2).with_z(height + 8),
324                Vec2::new(center.x - 6, center.y + 2).with_z(height),
325                0.8,
326            )
327            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
328            .fill(wood.clone());
329        //
330        painter
331            .line(
332                Vec2::new(center.x - 3, center.y - 12).with_z(height + 7),
333                Vec2::new(center.x - 3, center.y - 6).with_z(height),
334                0.8,
335            )
336            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
337            .fill(wood.clone());
338        painter
339            .line(
340                Vec2::new(center.x + 2, center.y - 12).with_z(height + 7),
341                Vec2::new(center.x + 2, center.y - 6).with_z(height),
342                0.8,
343            )
344            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
345            .fill(wood.clone());
346        //
347        painter
348            .line(
349                Vec2::new(center.x - 3, center.y + 5).with_z(height),
350                Vec2::new(center.x - 3, center.y + 9).with_z(height + 7),
351                0.8,
352            )
353            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
354            .fill(wood.clone());
355        painter
356            .line(
357                Vec2::new(center.x + 2, center.y + 5).with_z(height),
358                Vec2::new(center.x + 2, center.y + 9).with_z(height + 7),
359                0.8,
360            )
361            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
362            .fill(wood.clone());
363
364        //stairs
365        painter
366            .cylinder_with_radius(center.with_z(height + 8), 5.0, 1.0)
367            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
368            .clear();
369
370        let stairs_clear1 = painter.cylinder_with_radius(center.with_z(base), 5.0, 38.0);
371
372        painter
373            .prim(Primitive::sampling(
374                stairs_clear1,
375                spiral_staircase(center.with_z(base + 3), 6.0, 0.5, 9.0),
376            ))
377            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
378            .fill(wood.clone());
379
380        //clean up interface at top
381        painter
382            .aabb(Aabb {
383                min: Vec2::new(center.x + 1, center.y + 3).with_z(height + 8),
384                max: Vec2::new(center.x + 4, center.y + 5).with_z(height + 9),
385            })
386            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
387            .fill(wood.clone());
388        painter
389            .aabb(Aabb {
390                min: Vec2::new(center.x + 0, center.y + 2).with_z(height + 9),
391                max: Vec2::new(center.x + 6, center.y + 7).with_z(height + 10),
392            })
393            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
394            .fill(brick.clone());
395        painter
396            .aabb(Aabb {
397                min: Vec2::new(center.x + 1, center.y + 3).with_z(height + 9),
398                max: Vec2::new(center.x + 6, center.y + 7).with_z(height + 10),
399            })
400            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
401            .clear();
402        painter
403            .aabb(Aabb {
404                min: Vec2::new(center.x + 0, center.y + 2).with_z(height + 9),
405                max: Vec2::new(center.x + 1, center.y + 3).with_z(height + 17),
406            })
407            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
408            .fill(brick.clone());
409        //corner column
410        painter
411            .aabb(Aabb {
412                min: Vec2::new(center.x + 0, center.y + 2).with_z(height + 9),
413                max: Vec2::new(center.x + 1, center.y + 3).with_z(height + 17),
414            })
415            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
416            .fill(brick.clone());
417
418        let window_rot = if self.rotation == 0.0 || self.rotation == PI {
419            (2, 4)
420        } else {
421            (4, 2)
422        };
423        let sprite_fill = Fill::Block(
424            Block::air(SpriteKind::Window1)
425                .with_ori(window_rot.0)
426                .unwrap(),
427        );
428        //upper window
429        painter
430            .aabb(Aabb {
431                min: Vec2::new(center.x - 6, center.y - 1).with_z(height + 12),
432                max: Vec2::new(center.x - 5, center.y + 1).with_z(height + 15),
433            })
434            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
435            .fill(sprite_fill.clone());
436
437        //lower windows
438        painter
439            .aabb(Aabb {
440                min: Vec2::new(center.x - 6, center.y - 1).with_z(base + 19),
441                max: Vec2::new(center.x - 5, center.y + 1).with_z(base + 22),
442            })
443            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
444            .fill(sprite_fill.clone());
445        painter
446            .aabb(Aabb {
447                min: Vec2::new(center.x - 6, center.y - 1).with_z(base + 1),
448                max: Vec2::new(center.x - 5, center.y + 1).with_z(base + 4),
449            })
450            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
451            .fill(sprite_fill.clone());
452        painter
453            .aabb(Aabb {
454                min: Vec2::new(center.x + 5, center.y - 1).with_z(base + 4),
455                max: Vec2::new(center.x + 6, center.y + 1).with_z(base + 7),
456            })
457            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
458            .fill(sprite_fill.clone());
459        painter
460            .aabb(Aabb {
461                min: Vec2::new(center.x + 5, center.y - 1).with_z(base + 22),
462                max: Vec2::new(center.x + 6, center.y + 1).with_z(base + 25),
463            })
464            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
465            .fill(sprite_fill.clone());
466        painter
467            .aabb(Aabb {
468                min: Vec2::new(center.x + 5, center.y - 1).with_z(base + 30),
469                max: Vec2::new(center.x + 6, center.y + 1).with_z(base + 33),
470            })
471            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
472            .fill(sprite_fill.clone());
473
474        let sprite_fill = Fill::Block(
475            Block::air(SpriteKind::Window1)
476                .with_ori(window_rot.1)
477                .unwrap(),
478        );
479        //side windows
480        painter
481            .aabb(Aabb {
482                min: Vec2::new(center.x - 1, center.y + 5).with_z(base + 17),
483                max: Vec2::new(center.x + 1, center.y + 6).with_z(base + 20),
484            })
485            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
486            .fill(sprite_fill.clone());
487        painter
488            .aabb(Aabb {
489                min: Vec2::new(center.x - 1, center.y - 6).with_z(base + 13),
490                max: Vec2::new(center.x + 1, center.y - 5).with_z(base + 16),
491            })
492            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
493            .fill(sprite_fill.clone());
494
495        //lights
496        painter.rotated_sprite(
497            Vec2::new(center.x - 3, center.y + 5).with_z(base + 8),
498            SpriteKind::WallLampSmall,
499            4,
500        );
501        painter.rotated_sprite(
502            Vec2::new(center.x + 2, center.y + 5).with_z(base + 8),
503            SpriteKind::WallLampSmall,
504            4,
505        );
506        painter.rotated_sprite(
507            Vec2::new(center.x - 3, center.y + 5).with_z(base + 18),
508            SpriteKind::WallLampSmall,
509            4,
510        );
511        painter.rotated_sprite(
512            Vec2::new(center.x + 2, center.y + 5).with_z(base + 18),
513            SpriteKind::WallLampSmall,
514            4,
515        );
516        painter.rotated_sprite(
517            Vec2::new(center.x - 3, center.y - 6).with_z(base + 8),
518            SpriteKind::WallLampSmall,
519            0,
520        );
521        painter.rotated_sprite(
522            Vec2::new(center.x + 2, center.y - 6).with_z(base + 8),
523            SpriteKind::WallLampSmall,
524            0,
525        );
526        painter.rotated_sprite(
527            Vec2::new(center.x - 3, center.y - 6).with_z(base + 18),
528            SpriteKind::WallLampSmall,
529            0,
530        );
531        painter.rotated_sprite(
532            Vec2::new(center.x + 2, center.y - 6).with_z(base + 18),
533            SpriteKind::WallLampSmall,
534            0,
535        );
536
537        painter.rotated_sprite(
538            Vec2::new(center.x + 5, center.y - 3).with_z(base + 13),
539            SpriteKind::WallLampSmall,
540            2,
541        );
542        painter.rotated_sprite(
543            Vec2::new(center.x + 5, center.y + 2).with_z(base + 13),
544            SpriteKind::WallLampSmall,
545            2,
546        );
547        painter.rotated_sprite(
548            Vec2::new(center.x + 5, center.y - 3).with_z(base + 25),
549            SpriteKind::WallLampSmall,
550            2,
551        );
552        painter.rotated_sprite(
553            Vec2::new(center.x + 5, center.y + 2).with_z(base + 25),
554            SpriteKind::WallLampSmall,
555            2,
556        );
557        painter.rotated_sprite(
558            Vec2::new(center.x - 6, center.y - 3).with_z(base + 13),
559            SpriteKind::WallLampSmall,
560            6,
561        );
562        painter.rotated_sprite(
563            Vec2::new(center.x - 6, center.y + 2).with_z(base + 13),
564            SpriteKind::WallLampSmall,
565            6,
566        );
567        painter.rotated_sprite(
568            Vec2::new(center.x - 6, center.y - 3).with_z(base + 25),
569            SpriteKind::WallLampSmall,
570            6,
571        );
572        painter.rotated_sprite(
573            Vec2::new(center.x - 6, center.y + 2).with_z(base + 25),
574            SpriteKind::WallLampSmall,
575            6,
576        );
577        //upper lighting
578        for dir in DIAGONALS {
579            let pos = (center + dir * 12).with_z(height + 7);
580            painter.sprite(pos, SpriteKind::Lantern)
581        }
582        let sprite_fill = Fill::Block(Block::air(SpriteKind::Lantern).with_ori(2).unwrap());
583        //on cone lamps
584        painter
585            .aabb(Aabb {
586                min: Vec3::new(center.x - 6, center.y + 5, height + 16),
587                max: Vec3::new(center.x - 5, center.y + 6, height + 17),
588            })
589            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
590            .fill(sprite_fill.clone());
591        painter
592            .aabb(Aabb {
593                min: Vec3::new(center.x + 5, center.y + 5, height + 16),
594                max: Vec3::new(center.x + 6, center.y + 6, height + 17),
595            })
596            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
597            .fill(sprite_fill.clone());
598        painter
599            .aabb(Aabb {
600                min: Vec3::new(center.x - 6, center.y - 6, height + 16),
601                max: Vec3::new(center.x - 5, center.y - 5, height + 17),
602            })
603            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
604            .fill(sprite_fill.clone());
605        painter
606            .aabb(Aabb {
607                min: Vec3::new(center.x + 5, center.y - 6, height + 16),
608                max: Vec3::new(center.x + 6, center.y - 5, height + 17),
609            })
610            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
611            .fill(sprite_fill.clone());
612
613        //interior
614
615        painter
616            .aabb(Aabb {
617                min: Vec3::new(center.x - 2, center.y - 3, base + 6),
618                max: Vec3::new(center.x - 1, center.y + -2, base + 7),
619            })
620            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
621            .fill(sprite_fill.clone());
622        painter
623            .aabb(Aabb {
624                min: Vec3::new(center.x - 2, center.y - 3, base + 15),
625                max: Vec3::new(center.x - 1, center.y + -2, base + 16),
626            })
627            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
628            .fill(sprite_fill.clone());
629        painter
630            .aabb(Aabb {
631                min: Vec3::new(center.x - 2, center.y - 3, base + 24),
632                max: Vec3::new(center.x - 1, center.y + -2, base + 25),
633            })
634            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
635            .fill(sprite_fill.clone());
636        painter
637            .aabb(Aabb {
638                min: Vec3::new(center.x - 2, center.y - 3, base + 33),
639                max: Vec3::new(center.x - 1, center.y + -2, base + 34),
640            })
641            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
642            .fill(sprite_fill.clone());
643        painter
644            .aabb(Aabb {
645                min: Vec3::new(center.x - 2, center.y - 3, base + 44),
646                max: Vec3::new(center.x - 1, center.y + -2, base + 45),
647            })
648            .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
649            .fill(sprite_fill.clone());
650
651        // crate and barrel sprites
652        let mut sprite_positions = vec![];
653        for a in 0..5 {
654            sprite_positions.push(Vec2::new(center.x + 1 + a, center.y + 2));
655        }
656        for b in 0..=1 {
657            sprite_positions.push(Vec2::new(center.x, center.y + 3 + b));
658        }
659        for sprite_pos in sprite_positions {
660            let rows = (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
661            for r in 0..rows {
662                painter
663                    .aabb(Aabb {
664                        min: sprite_pos.with_z(height + 10 + r),
665                        max: (sprite_pos + 1).with_z(height + 11 + r),
666                    })
667                    .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base))
668                    .fill(Fill::Block(Block::air(
669                        match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2) as i32 {
670                            0 => SpriteKind::Barrel,
671                            _ => SpriteKind::CrateBlock,
672                        },
673                    )));
674            }
675        }
676        // campfire
677        painter.spawn(
678            EntityInfo::at(self.campfire_pos.map(|e| e as f32 + 0.5))
679                .into_special(SpecialEntity::Waypoint),
680        );
681        // docks
682        for dir in CARDINALS {
683            let pos = (center + dir * 15).with_z(height + 9);
684            painter
685                .cylinder_with_radius(pos, 5.0, 1.0)
686                .fill(wood.clone());
687        }
688    }
689}