veloren_world/site/plot/
giant_tree.rs1use crate::{
2 Land, Sampler, SpriteKind,
3 layer::tree::{ProceduralTree, TreeConfig},
4 site::{Fill, Painter, Site, Structure, namegen::NameGen},
5 util::FastNoise,
6};
7use common::{
8 generation::EntityInfo,
9 terrain::{Block, BlockKind},
10};
11use rand::RngExt;
12use vek::*;
13
14pub struct GiantTree {
15 name: String,
16 wpos: Vec3<i32>,
17 tree: ProceduralTree,
18 seed: u32,
19}
20
21impl GiantTree {
22 pub fn generate(
23 site: &Site,
24 center_tile: Vec2<i32>,
25 land: &Land,
26 rng: &mut impl RngExt,
27 ) -> Self {
28 let wpos = site.tile_center_wpos(center_tile);
29 Self {
30 name: format!("Tree of {}", NameGen::location(rng).generate()),
31 wpos: wpos.with_z(land.get_alt_approx(wpos) as i32),
33 tree: {
34 let config = TreeConfig::giant(rng, 4.0, true);
35 ProceduralTree::generate(config, rng)
36 },
37 seed: rng.random(),
38 }
39 }
40
41 pub fn name(&self) -> &str { &self.name }
42
43 pub fn radius(&self) -> f32 { 100.0 }
44
45 pub fn tree(&self) -> &ProceduralTree { &self.tree }
46
47 pub fn entity_at(
48 &self,
49 pos: Vec3<i32>,
50 above_block: &Block,
51 dynamic_rng: &mut impl RngExt,
52 ) -> Option<EntityInfo> {
53 if above_block.kind() == BlockKind::Leaves && dynamic_rng.random_bool(0.000055) {
54 let entity = EntityInfo::at(pos.as_());
55 match dynamic_rng.random_range(0..=7) {
56 0 => Some(entity.with_asset_expect(
57 "common.entity.wild.aggressive.horn_beetle",
58 dynamic_rng,
59 None,
60 )),
61 1 => Some(entity.with_asset_expect(
62 "common.entity.wild.aggressive.stag_beetle",
63 dynamic_rng,
64 None,
65 )),
66 2..=3 => Some(entity.with_asset_expect(
67 "common.entity.wild.aggressive.deadwood",
68 dynamic_rng,
69 None,
70 )),
71 4 => Some(entity.with_asset_expect(
72 "common.entity.wild.aggressive.maneater",
73 dynamic_rng,
74 None,
75 )),
76 5..=7 => Some(entity.with_asset_expect(
77 "common.entity.wild.peaceful.parrot",
78 dynamic_rng,
79 None,
80 )),
81 _ => None,
82 }
83 } else {
84 None
85 }
86 }
87
88 pub fn leaf_color(&self) -> Rgb<u8> {
89 let fast_noise = FastNoise::new(self.seed);
90 let dark = Rgb::new(10, 70, 50).map(|e| e as f32);
91 let light = Rgb::new(80, 140, 10).map(|e| e as f32);
92 Lerp::lerp(
93 dark,
94 light,
95 fast_noise.get((self.wpos.map(|e| e as f64) * 0.05) * 0.5 + 0.5),
96 )
97 .map(|e| e as u8)
98 }
99}
100
101impl Structure for GiantTree {
102 #[cfg(feature = "dyn-lib")]
103 #[unsafe(export_name = "as_dyn_structure_gianttree")]
104 fn as_dyn_outer(&self) -> Option<(&dyn Structure, &'static str)> {
105 Some((Self::as_dyn_impl(self), "as_dyn_structure_gianttree"))
106 }
107
108 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
109 let leaf_col = self.leaf_color();
110 let mut rng = rand::rng();
111 self.tree.walk(|branch, parent| {
112 let aabr = Aabr {
113 min: self.wpos.xy() + branch.get_aabb().min.xy().as_(),
114 max: self.wpos.xy() + branch.get_aabb().max.xy().as_(),
115 };
116 if aabr.collides_with_aabr(painter.render_aabr().as_()) {
117 painter
118 .line_two_radius(
119 self.wpos + branch.get_line().start.as_(),
120 self.wpos + branch.get_line().end.as_(),
121 parent.get_wood_radius(),
122 branch.get_wood_radius(),
123 )
124 .fill(Fill::Block(Block::new(
125 BlockKind::Wood,
126 Rgb::new(80, 32, 0),
127 )));
128 if branch.get_leaf_radius() > branch.get_wood_radius() {
129 painter
130 .line_two_radius(
131 self.wpos + branch.get_line().start.as_(),
132 self.wpos + branch.get_line().end.as_(),
133 parent.get_leaf_radius(),
134 branch.get_leaf_radius(),
135 )
136 .fill(Fill::Block(Block::new(BlockKind::Leaves, leaf_col)));
137 let branch_start = branch.get_line().start;
139 let branch_end = branch.get_line().end;
140 let branch_direction = (branch_end - branch_start).normalized();
141
142 let displacement =
144 (branch_direction * branch.get_leaf_radius()).map(|e| e.round() as i32);
145 let pos = self.wpos + branch_end.as_() + displacement;
146 if rng.random_bool(0.07) {
147 let ori = rng.random_range(0..=3) * 2;
148 painter.resource_sprite(pos, SpriteKind::Ironwood, ori);
149 }
150 }
151 true
152 } else {
153 false
154 }
155 });
156 }
157}