Skip to main content

steel_core/worldgen/feature/features/
huge_fungus.rs

1use super::super::prelude::*;
2use super::super::runner::FeatureDecorationRunner;
3
4impl FeatureDecorationRunner {
5    pub(in crate::worldgen::feature) fn place_huge_fungus_feature(
6        region: &mut WorldGenRegion<'_>,
7        registry: &Registry,
8        random: &mut WorldgenRandom,
9        config: &HugeFungusConfiguration,
10        origin: BlockPos,
11    ) -> bool {
12        let valid_base_state = Self::block_state_from_data(registry, &config.valid_base_block);
13        if region.block_state(origin.below()).get_block() != valid_base_state.get_block() {
14            return false;
15        }
16
17        let mut total_height = random.next_i32_between(4, 13);
18        if random.next_i32_bounded(12) == 0 {
19            total_height *= 2;
20        }
21
22        if !config.planted && origin.y() + total_height + 1 >= region.generation_height() {
23            return false;
24        }
25
26        let stem_state = Self::block_state_from_data(registry, &config.stem_state);
27        let hat_state = Self::block_state_from_data(registry, &config.hat_state);
28        let decor_state = Self::block_state_from_data(registry, &config.decor_state);
29        let is_huge = !config.planted && random.next_f32() < 0.06;
30        let _ = region.set_block_state(
31            origin,
32            vanilla_blocks::AIR.default_state(),
33            UpdateFlags::UPDATE_NONE,
34        );
35
36        Self::place_huge_fungus_stem(
37            region,
38            registry,
39            random,
40            config,
41            origin,
42            stem_state,
43            total_height,
44            is_huge,
45        );
46        Self::place_huge_fungus_hat(
47            region,
48            registry,
49            random,
50            config,
51            origin,
52            hat_state,
53            decor_state,
54            total_height,
55            is_huge,
56        );
57        true
58    }
59
60    #[expect(
61        clippy::too_many_arguments,
62        reason = "mirrors vanilla HugeFungusFeature.placeStem state"
63    )]
64    fn place_huge_fungus_stem(
65        region: &mut WorldGenRegion<'_>,
66        registry: &Registry,
67        random: &mut WorldgenRandom,
68        config: &HugeFungusConfiguration,
69        origin: BlockPos,
70        stem_state: BlockStateId,
71        total_height: i32,
72        is_huge: bool,
73    ) {
74        let stem_radius: i32 = i32::from(is_huge);
75
76        for dx in -stem_radius..=stem_radius {
77            for dz in -stem_radius..=stem_radius {
78                let corner_of_huge_stem =
79                    is_huge && dx.abs() == stem_radius && dz.abs() == stem_radius;
80
81                for dy in 0..total_height {
82                    let pos = origin.offset(dx, dy, dz);
83                    if !Self::huge_fungus_is_replaceable(region, registry, pos, config, true) {
84                        continue;
85                    }
86
87                    if config.planted {
88                        if !region.block_state(pos.below()).is_air() {
89                            let _ = region.set_block_state(
90                                pos,
91                                vanilla_blocks::AIR.default_state(),
92                                UpdateFlags::UPDATE_NONE,
93                            );
94                        }
95
96                        let _ = region.set_block_state(pos, stem_state, UpdateFlags::UPDATE_ALL);
97                    } else if corner_of_huge_stem {
98                        if random.next_f32() < 0.1 {
99                            let _ =
100                                region.set_block_state(pos, stem_state, UpdateFlags::UPDATE_ALL);
101                        }
102                    } else {
103                        let _ = region.set_block_state(pos, stem_state, UpdateFlags::UPDATE_ALL);
104                    }
105                }
106            }
107        }
108    }
109
110    #[expect(
111        clippy::too_many_arguments,
112        reason = "mirrors vanilla HugeFungusFeature.placeHat state"
113    )]
114    fn place_huge_fungus_hat(
115        region: &mut WorldGenRegion<'_>,
116        registry: &Registry,
117        random: &mut WorldgenRandom,
118        config: &HugeFungusConfiguration,
119        origin: BlockPos,
120        hat_state: BlockStateId,
121        decor_state: BlockStateId,
122        total_height: i32,
123        is_huge: bool,
124    ) {
125        let place_vines = hat_state.get_block() == &vanilla_blocks::NETHER_WART_BLOCK;
126        let hat_height = (random.next_i32_bounded(1 + total_height / 3) + 5).min(total_height);
127        let hat_start_y = total_height - hat_height;
128
129        for dy in hat_start_y..=total_height {
130            let mut radius = if dy < total_height - random.next_i32_bounded(3) {
131                2
132            } else {
133                1
134            };
135            if hat_height > 8 && dy < hat_start_y + 4 {
136                radius = 3;
137            }
138
139            if is_huge {
140                radius += 1;
141            }
142
143            for dx in -radius..=radius {
144                for dz in -radius..=radius {
145                    let is_edge_x = dx == -radius || dx == radius;
146                    let is_edge_z = dz == -radius || dz == radius;
147                    let inside = !is_edge_x && !is_edge_z && dy != total_height;
148                    let corner = is_edge_x && is_edge_z;
149                    let is_hat_bottom = dy < hat_start_y + 3;
150                    let pos = origin.offset(dx, dy, dz);
151
152                    if !Self::huge_fungus_is_replaceable(region, registry, pos, config, false) {
153                        continue;
154                    }
155
156                    if config.planted && !region.block_state(pos.below()).is_air() {
157                        let _ = region.set_block_state(
158                            pos,
159                            vanilla_blocks::AIR.default_state(),
160                            UpdateFlags::UPDATE_NONE,
161                        );
162                    }
163
164                    if is_hat_bottom {
165                        if !inside {
166                            Self::place_huge_fungus_hat_drop_block(
167                                region,
168                                random,
169                                pos,
170                                hat_state,
171                                place_vines,
172                            );
173                        }
174                    } else if inside {
175                        Self::place_huge_fungus_hat_block(
176                            region,
177                            random,
178                            pos,
179                            hat_state,
180                            decor_state,
181                            0.1,
182                            0.2,
183                            if place_vines { 0.1 } else { 0.0 },
184                        );
185                    } else if corner {
186                        Self::place_huge_fungus_hat_block(
187                            region,
188                            random,
189                            pos,
190                            hat_state,
191                            decor_state,
192                            0.01,
193                            0.7,
194                            if place_vines { 0.083 } else { 0.0 },
195                        );
196                    } else {
197                        Self::place_huge_fungus_hat_block(
198                            region,
199                            random,
200                            pos,
201                            hat_state,
202                            decor_state,
203                            5.0E-4,
204                            0.98,
205                            if place_vines { 0.07 } else { 0.0 },
206                        );
207                    }
208                }
209            }
210        }
211    }
212
213    #[expect(
214        clippy::too_many_arguments,
215        reason = "vanilla hat placement uses three independent probabilities"
216    )]
217    fn place_huge_fungus_hat_block(
218        region: &mut WorldGenRegion<'_>,
219        random: &mut WorldgenRandom,
220        pos: BlockPos,
221        hat_state: BlockStateId,
222        decor_state: BlockStateId,
223        decor_block_probability: f32,
224        hat_block_probability: f32,
225        vines_probability: f32,
226    ) {
227        if random.next_f32() < decor_block_probability {
228            let _ = region.set_block_state(pos, decor_state, UpdateFlags::UPDATE_ALL);
229        } else if random.next_f32() < hat_block_probability {
230            let _ = region.set_block_state(pos, hat_state, UpdateFlags::UPDATE_ALL);
231            if random.next_f32() < vines_probability {
232                Self::try_place_huge_fungus_weeping_vines(region, random, pos);
233            }
234        }
235    }
236
237    fn place_huge_fungus_hat_drop_block(
238        region: &mut WorldGenRegion<'_>,
239        random: &mut WorldgenRandom,
240        pos: BlockPos,
241        hat_state: BlockStateId,
242        place_vines: bool,
243    ) {
244        if region.block_state(pos.below()).get_block() == hat_state.get_block() {
245            let _ = region.set_block_state(pos, hat_state, UpdateFlags::UPDATE_ALL);
246        } else if random.next_f32() < 0.15 {
247            let _ = region.set_block_state(pos, hat_state, UpdateFlags::UPDATE_ALL);
248            if place_vines && random.next_i32_bounded(11) == 0 {
249                Self::try_place_huge_fungus_weeping_vines(region, random, pos);
250            }
251        }
252    }
253
254    fn try_place_huge_fungus_weeping_vines(
255        region: &mut WorldGenRegion<'_>,
256        random: &mut WorldgenRandom,
257        hat_pos: BlockPos,
258    ) {
259        let place_pos = hat_pos.below();
260        if !region.block_state(place_pos).is_air() {
261            return;
262        }
263
264        let mut goal_vine_height = random.next_i32_between(1, 5);
265        if random.next_i32_bounded(7) == 0 {
266            goal_vine_height *= 2;
267        }
268
269        Self::place_weeping_vines_column(region, random, place_pos, goal_vine_height, 23, 25);
270    }
271
272    fn huge_fungus_is_replaceable(
273        region: &WorldGenRegion<'_>,
274        registry: &Registry,
275        pos: BlockPos,
276        config: &HugeFungusConfiguration,
277        check_non_replaceable_plants: bool,
278    ) -> bool {
279        if region.block_state(pos).is_replaceable() {
280            return true;
281        }
282
283        check_non_replaceable_plants
284            && Self::test_block_predicate(region, registry, &config.replaceable_blocks, pos)
285    }
286}