Skip to main content

steel_core/worldgen/structure/piece_placer/
fortress.rs

1use steel_registry::blocks::block_state_ext::BlockStateExt as _;
2use steel_registry::blocks::properties::BlockStateProperties;
3use steel_registry::{Registry, vanilla_blocks};
4use steel_utils::random::Random;
5use steel_utils::random::legacy_random::LegacyRandom;
6use steel_utils::random::worldgen_random::WorldgenRandom;
7use steel_utils::{BlockStateId, BoundingBox, Direction};
8
9use crate::worldgen::region::WorldGenRegion;
10use steel_worldgen::structure::fortress::FortressPieceData;
11
12use super::{StructurePiecePlacer, scattered_feature::ScatteredFeaturePlacer};
13
14const NETHER_BRIDGE_LOOT: &str = "minecraft:chests/nether_bridge";
15const BLAZE_ENTITY: &str = "minecraft:blaze";
16
17impl StructurePiecePlacer {
18    pub(super) fn place_nether_fortress_piece(
19        region: &mut WorldGenRegion<'_>,
20        registry: &Registry,
21        bounding_box: BoundingBox,
22        orientation: Option<Direction>,
23        data: &mut FortressPieceData,
24        clip: BoundingBox,
25        random: &mut WorldgenRandom,
26    ) -> bool {
27        let Some(
28            orientation @ (Direction::North | Direction::South | Direction::West | Direction::East),
29        ) = orientation
30        else {
31            return false;
32        };
33        let mut piece_bounding_box = bounding_box;
34        let mut placer = ScatteredFeaturePlacer::new(
35            region,
36            registry,
37            &mut piece_bounding_box,
38            Some(orientation),
39            clip,
40        );
41        match data {
42            FortressPieceData::BridgeCrossing => place_bridge_crossing(&mut placer),
43            FortressPieceData::BridgeEndFiller { self_seed } => {
44                place_bridge_end_filler(&mut placer, *self_seed);
45            }
46            FortressPieceData::BridgeStraight => place_bridge_straight(&mut placer),
47            FortressPieceData::CastleCorridorStairs => place_castle_corridor_stairs(&mut placer),
48            FortressPieceData::CastleCorridorTBalcony => {
49                place_castle_corridor_t_balcony(&mut placer);
50            }
51            FortressPieceData::CastleEntrance => place_castle_entrance(&mut placer),
52            FortressPieceData::CastleSmallCorridorCrossing => {
53                place_castle_small_corridor_crossing(&mut placer);
54            }
55            FortressPieceData::CastleSmallCorridorLeftTurn { is_needing_chest } => {
56                place_castle_small_corridor_left_turn(&mut placer, random, is_needing_chest);
57            }
58            FortressPieceData::CastleSmallCorridor => place_castle_small_corridor(&mut placer),
59            FortressPieceData::CastleSmallCorridorRightTurn { is_needing_chest } => {
60                place_castle_small_corridor_right_turn(&mut placer, random, is_needing_chest);
61            }
62            FortressPieceData::CastleStalkRoom => place_castle_stalk_room(&mut placer),
63            FortressPieceData::MonsterThrone { has_placed_spawner } => {
64                place_monster_throne(&mut placer, has_placed_spawner);
65            }
66            FortressPieceData::RoomCrossing => place_room_crossing(&mut placer),
67            FortressPieceData::StairsRoom => place_stairs_room(&mut placer),
68        }
69        true
70    }
71}
72
73fn nether_bricks() -> BlockStateId {
74    vanilla_blocks::NETHER_BRICKS.default_state()
75}
76
77fn air() -> BlockStateId {
78    vanilla_blocks::AIR.default_state()
79}
80
81fn lava() -> BlockStateId {
82    vanilla_blocks::LAVA.default_state()
83}
84
85fn soul_sand() -> BlockStateId {
86    vanilla_blocks::SOUL_SAND.default_state()
87}
88
89fn nether_wart() -> BlockStateId {
90    vanilla_blocks::NETHER_WART.default_state()
91}
92
93fn stairs(facing: Direction) -> BlockStateId {
94    vanilla_blocks::NETHER_BRICK_STAIRS
95        .default_state()
96        .set_value(&BlockStateProperties::FACING, facing)
97}
98
99const FENCE_NORTH: u8 = 1;
100const FENCE_EAST: u8 = 2;
101const FENCE_SOUTH: u8 = 4;
102const FENCE_WEST: u8 = 8;
103
104fn fence(mask: u8) -> BlockStateId {
105    vanilla_blocks::NETHER_BRICK_FENCE
106        .default_state()
107        .set_value(&BlockStateProperties::NORTH, mask & FENCE_NORTH != 0)
108        .set_value(&BlockStateProperties::EAST, mask & FENCE_EAST != 0)
109        .set_value(&BlockStateProperties::SOUTH, mask & FENCE_SOUTH != 0)
110        .set_value(&BlockStateProperties::WEST, mask & FENCE_WEST != 0)
111}
112
113fn fence_ns() -> BlockStateId {
114    fence(FENCE_NORTH | FENCE_SOUTH)
115}
116
117fn fence_we() -> BlockStateId {
118    fence(FENCE_EAST | FENCE_WEST)
119}
120
121fn place_bridge_crossing(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
122    let bricks = nether_bricks();
123    let air = air();
124    placer.generate_box(7, 3, 0, 11, 4, 18, bricks, bricks, false);
125    placer.generate_box(0, 3, 7, 18, 4, 11, bricks, bricks, false);
126    placer.generate_box(8, 5, 0, 10, 7, 18, air, air, false);
127    placer.generate_box(0, 5, 8, 18, 7, 10, air, air, false);
128    placer.generate_box(7, 5, 0, 7, 5, 7, bricks, bricks, false);
129    placer.generate_box(7, 5, 11, 7, 5, 18, bricks, bricks, false);
130    placer.generate_box(11, 5, 0, 11, 5, 7, bricks, bricks, false);
131    placer.generate_box(11, 5, 11, 11, 5, 18, bricks, bricks, false);
132    placer.generate_box(0, 5, 7, 7, 5, 7, bricks, bricks, false);
133    placer.generate_box(11, 5, 7, 18, 5, 7, bricks, bricks, false);
134    placer.generate_box(0, 5, 11, 7, 5, 11, bricks, bricks, false);
135    placer.generate_box(11, 5, 11, 18, 5, 11, bricks, bricks, false);
136    placer.generate_box(7, 2, 0, 11, 2, 5, bricks, bricks, false);
137    placer.generate_box(7, 2, 13, 11, 2, 18, bricks, bricks, false);
138    placer.generate_box(7, 0, 0, 11, 1, 3, bricks, bricks, false);
139    placer.generate_box(7, 0, 15, 11, 1, 18, bricks, bricks, false);
140
141    for x in 7..=11 {
142        for z in 0..=2 {
143            placer.fill_column_down(bricks, x, -1, z);
144            placer.fill_column_down(bricks, x, -1, 18 - z);
145        }
146    }
147
148    placer.generate_box(0, 2, 7, 5, 2, 11, bricks, bricks, false);
149    placer.generate_box(13, 2, 7, 18, 2, 11, bricks, bricks, false);
150    placer.generate_box(0, 0, 7, 3, 1, 11, bricks, bricks, false);
151    placer.generate_box(15, 0, 7, 18, 1, 11, bricks, bricks, false);
152
153    for x in 0..=2 {
154        for z in 7..=11 {
155            placer.fill_column_down(bricks, x, -1, z);
156            placer.fill_column_down(bricks, 18 - x, -1, z);
157        }
158    }
159}
160
161fn place_bridge_end_filler(placer: &mut ScatteredFeaturePlacer<'_, '_>, self_seed: i32) {
162    let mut self_random = LegacyRandom::from_seed(i64::from(self_seed) as u64);
163    let bricks = nether_bricks();
164
165    for x in 0..=4 {
166        for y in 3..=4 {
167            let z = self_random.next_i32_bounded(8);
168            placer.generate_box(x, y, 0, x, y, z, bricks, bricks, false);
169        }
170    }
171
172    let z = self_random.next_i32_bounded(8);
173    placer.generate_box(0, 5, 0, 0, 5, z, bricks, bricks, false);
174    let z = self_random.next_i32_bounded(8);
175    placer.generate_box(4, 5, 0, 4, 5, z, bricks, bricks, false);
176
177    for x in 0..=4 {
178        let z = self_random.next_i32_bounded(5);
179        placer.generate_box(x, 2, 0, x, 2, z, bricks, bricks, false);
180    }
181
182    for x in 0..=4 {
183        for y in 0..=1 {
184            let z = self_random.next_i32_bounded(3);
185            placer.generate_box(x, y, 0, x, y, z, bricks, bricks, false);
186        }
187    }
188}
189
190#[expect(
191    clippy::too_many_lines,
192    reason = "straight transcription of vanilla NetherFortressPieces.BridgeStraight"
193)]
194fn place_bridge_straight(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
195    let bricks = nether_bricks();
196    let air = air();
197    placer.generate_box(0, 3, 0, 4, 4, 18, bricks, bricks, false);
198    placer.generate_box(1, 5, 0, 3, 7, 18, air, air, false);
199    placer.generate_box(0, 5, 0, 0, 5, 18, bricks, bricks, false);
200    placer.generate_box(4, 5, 0, 4, 5, 18, bricks, bricks, false);
201    placer.generate_box(0, 2, 0, 4, 2, 5, bricks, bricks, false);
202    placer.generate_box(0, 2, 13, 4, 2, 18, bricks, bricks, false);
203    placer.generate_box(0, 0, 0, 4, 1, 3, bricks, bricks, false);
204    placer.generate_box(0, 0, 15, 4, 1, 18, bricks, bricks, false);
205
206    for x in 0..=4 {
207        for z in 0..=2 {
208            placer.fill_column_down(bricks, x, -1, z);
209            placer.fill_column_down(bricks, x, -1, 18 - z);
210        }
211    }
212
213    let north_south_east_fence = fence(FENCE_NORTH | FENCE_SOUTH | FENCE_EAST);
214    let north_south_west_fence = fence(FENCE_NORTH | FENCE_SOUTH | FENCE_WEST);
215    placer.generate_box(
216        0,
217        1,
218        1,
219        0,
220        4,
221        1,
222        north_south_east_fence,
223        north_south_east_fence,
224        false,
225    );
226    placer.generate_box(
227        0,
228        3,
229        4,
230        0,
231        4,
232        4,
233        north_south_east_fence,
234        north_south_east_fence,
235        false,
236    );
237    placer.generate_box(
238        0,
239        3,
240        14,
241        0,
242        4,
243        14,
244        north_south_east_fence,
245        north_south_east_fence,
246        false,
247    );
248    placer.generate_box(
249        0,
250        1,
251        17,
252        0,
253        4,
254        17,
255        north_south_east_fence,
256        north_south_east_fence,
257        false,
258    );
259    placer.generate_box(
260        4,
261        1,
262        1,
263        4,
264        4,
265        1,
266        north_south_west_fence,
267        north_south_west_fence,
268        false,
269    );
270    placer.generate_box(
271        4,
272        3,
273        4,
274        4,
275        4,
276        4,
277        north_south_west_fence,
278        north_south_west_fence,
279        false,
280    );
281    placer.generate_box(
282        4,
283        3,
284        14,
285        4,
286        4,
287        14,
288        north_south_west_fence,
289        north_south_west_fence,
290        false,
291    );
292    placer.generate_box(
293        4,
294        1,
295        17,
296        4,
297        4,
298        17,
299        north_south_west_fence,
300        north_south_west_fence,
301        false,
302    );
303}
304
305fn place_castle_corridor_stairs(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
306    let bricks = nether_bricks();
307    let air = air();
308    let stairs = stairs(Direction::South);
309    let ns_fence = fence_ns();
310
311    for step in 0..=9 {
312        let floor = 1.max(7 - step);
313        let roof = (floor + 5).max(14 - step).min(13);
314        placer.generate_box(0, 0, step, 4, floor, step, bricks, bricks, false);
315        placer.generate_box(1, floor + 1, step, 3, roof - 1, step, air, air, false);
316        if step <= 6 {
317            placer.place_block(stairs, 1, floor + 1, step);
318            placer.place_block(stairs, 2, floor + 1, step);
319            placer.place_block(stairs, 3, floor + 1, step);
320        }
321
322        placer.generate_box(0, roof, step, 4, roof, step, bricks, bricks, false);
323        placer.generate_box(0, floor + 1, step, 0, roof - 1, step, bricks, bricks, false);
324        placer.generate_box(4, floor + 1, step, 4, roof - 1, step, bricks, bricks, false);
325        if (step & 1) == 0 {
326            placer.generate_box(
327                0,
328                floor + 2,
329                step,
330                0,
331                floor + 3,
332                step,
333                ns_fence,
334                ns_fence,
335                false,
336            );
337            placer.generate_box(
338                4,
339                floor + 2,
340                step,
341                4,
342                floor + 3,
343                step,
344                ns_fence,
345                ns_fence,
346                false,
347            );
348        }
349
350        for x in 0..=4 {
351            placer.fill_column_down(bricks, x, -1, step);
352        }
353    }
354}
355
356fn place_castle_corridor_t_balcony(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
357    let bricks = nether_bricks();
358    let air = air();
359    let ns_fence = fence_ns();
360    let we_fence = fence_we();
361    placer.generate_box(0, 0, 0, 8, 1, 8, bricks, bricks, false);
362    placer.generate_box(0, 2, 0, 8, 5, 8, air, air, false);
363    placer.generate_box(0, 6, 0, 8, 6, 5, bricks, bricks, false);
364    placer.generate_box(0, 2, 0, 2, 5, 0, bricks, bricks, false);
365    placer.generate_box(6, 2, 0, 8, 5, 0, bricks, bricks, false);
366    placer.generate_box(1, 3, 0, 1, 4, 0, we_fence, we_fence, false);
367    placer.generate_box(7, 3, 0, 7, 4, 0, we_fence, we_fence, false);
368    placer.generate_box(0, 2, 4, 8, 2, 8, bricks, bricks, false);
369    placer.generate_box(1, 1, 4, 2, 2, 4, air, air, false);
370    placer.generate_box(6, 1, 4, 7, 2, 4, air, air, false);
371    placer.generate_box(1, 3, 8, 7, 3, 8, we_fence, we_fence, false);
372    placer.place_block(fence(FENCE_EAST | FENCE_SOUTH), 0, 3, 8);
373    placer.place_block(fence(FENCE_SOUTH | FENCE_WEST), 8, 3, 8);
374    placer.generate_box(0, 3, 6, 0, 3, 7, ns_fence, ns_fence, false);
375    placer.generate_box(8, 3, 6, 8, 3, 7, ns_fence, ns_fence, false);
376    placer.generate_box(0, 3, 4, 0, 5, 5, bricks, bricks, false);
377    placer.generate_box(8, 3, 4, 8, 5, 5, bricks, bricks, false);
378    placer.generate_box(1, 3, 5, 2, 5, 5, bricks, bricks, false);
379    placer.generate_box(6, 3, 5, 7, 5, 5, bricks, bricks, false);
380    placer.generate_box(1, 4, 5, 1, 5, 5, we_fence, we_fence, false);
381    placer.generate_box(7, 4, 5, 7, 5, 5, we_fence, we_fence, false);
382
383    for z in 0..=5 {
384        for x in 0..=8 {
385            placer.fill_column_down(bricks, x, -1, z);
386        }
387    }
388}
389
390fn place_castle_entrance(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
391    let bricks = nether_bricks();
392    let air = air();
393    let we_fence = fence_we();
394    let ns_fence = fence_ns();
395    placer.generate_box(0, 3, 0, 12, 4, 12, bricks, bricks, false);
396    placer.generate_box(0, 5, 0, 12, 13, 12, air, air, false);
397    placer.generate_box(0, 5, 0, 1, 12, 12, bricks, bricks, false);
398    placer.generate_box(11, 5, 0, 12, 12, 12, bricks, bricks, false);
399    placer.generate_box(2, 5, 11, 4, 12, 12, bricks, bricks, false);
400    placer.generate_box(8, 5, 11, 10, 12, 12, bricks, bricks, false);
401    placer.generate_box(5, 9, 11, 7, 12, 12, bricks, bricks, false);
402    placer.generate_box(2, 5, 0, 4, 12, 1, bricks, bricks, false);
403    placer.generate_box(8, 5, 0, 10, 12, 1, bricks, bricks, false);
404    placer.generate_box(5, 9, 0, 7, 12, 1, bricks, bricks, false);
405    placer.generate_box(2, 11, 2, 10, 12, 10, bricks, bricks, false);
406    placer.generate_box(5, 8, 0, 7, 8, 0, fence(0), fence(0), false);
407
408    for i in (1..=11).step_by(2) {
409        placer.generate_box(i, 10, 0, i, 11, 0, we_fence, we_fence, false);
410        placer.generate_box(i, 10, 12, i, 11, 12, we_fence, we_fence, false);
411        placer.generate_box(0, 10, i, 0, 11, i, ns_fence, ns_fence, false);
412        placer.generate_box(12, 10, i, 12, 11, i, ns_fence, ns_fence, false);
413        placer.place_block(bricks, i, 13, 0);
414        placer.place_block(bricks, i, 13, 12);
415        placer.place_block(bricks, 0, 13, i);
416        placer.place_block(bricks, 12, 13, i);
417        if i != 11 {
418            placer.place_block(we_fence, i + 1, 13, 0);
419            placer.place_block(we_fence, i + 1, 13, 12);
420            placer.place_block(ns_fence, 0, 13, i + 1);
421            placer.place_block(ns_fence, 12, 13, i + 1);
422        }
423    }
424
425    placer.place_block(fence(FENCE_NORTH | FENCE_EAST), 0, 13, 0);
426    placer.place_block(fence(FENCE_EAST | FENCE_SOUTH), 0, 13, 12);
427    placer.place_block(fence(FENCE_SOUTH | FENCE_WEST), 12, 13, 12);
428    placer.place_block(fence(FENCE_NORTH | FENCE_WEST), 12, 13, 0);
429
430    for z in (3..=9).step_by(2) {
431        placer.generate_box(
432            1,
433            7,
434            z,
435            1,
436            8,
437            z,
438            fence(FENCE_NORTH | FENCE_SOUTH | FENCE_WEST),
439            fence(FENCE_NORTH | FENCE_SOUTH | FENCE_WEST),
440            false,
441        );
442        placer.generate_box(
443            11,
444            7,
445            z,
446            11,
447            8,
448            z,
449            fence(FENCE_NORTH | FENCE_EAST | FENCE_SOUTH),
450            fence(FENCE_NORTH | FENCE_EAST | FENCE_SOUTH),
451            false,
452        );
453    }
454
455    place_castle_cross_foundation(placer);
456    placer.generate_box(5, 5, 5, 7, 5, 7, bricks, bricks, false);
457    placer.generate_box(6, 1, 6, 6, 4, 6, air, air, false);
458    placer.place_block(bricks, 6, 0, 6);
459    placer.place_block(lava(), 6, 5, 6);
460}
461
462fn place_castle_small_corridor_crossing(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
463    let bricks = nether_bricks();
464    let air = air();
465    placer.generate_box(0, 0, 0, 4, 1, 4, bricks, bricks, false);
466    placer.generate_box(0, 2, 0, 4, 5, 4, air, air, false);
467    placer.generate_box(0, 2, 0, 0, 5, 0, bricks, bricks, false);
468    placer.generate_box(4, 2, 0, 4, 5, 0, bricks, bricks, false);
469    placer.generate_box(0, 2, 4, 0, 5, 4, bricks, bricks, false);
470    placer.generate_box(4, 2, 4, 4, 5, 4, bricks, bricks, false);
471    placer.generate_box(0, 6, 0, 4, 6, 4, bricks, bricks, false);
472    fill_down_square(placer, 4, 4);
473}
474
475fn place_castle_small_corridor_left_turn(
476    placer: &mut ScatteredFeaturePlacer<'_, '_>,
477    random: &mut WorldgenRandom,
478    is_needing_chest: &mut bool,
479) {
480    let bricks = nether_bricks();
481    let air = air();
482    let we_fence = fence_we();
483    let ns_fence = fence_ns();
484    placer.generate_box(0, 0, 0, 4, 1, 4, bricks, bricks, false);
485    placer.generate_box(0, 2, 0, 4, 5, 4, air, air, false);
486    placer.generate_box(4, 2, 0, 4, 5, 4, bricks, bricks, false);
487    placer.generate_box(4, 3, 1, 4, 4, 1, ns_fence, ns_fence, false);
488    placer.generate_box(4, 3, 3, 4, 4, 3, ns_fence, ns_fence, false);
489    placer.generate_box(0, 2, 0, 0, 5, 0, bricks, bricks, false);
490    placer.generate_box(0, 2, 4, 3, 5, 4, bricks, bricks, false);
491    placer.generate_box(1, 3, 4, 1, 4, 4, we_fence, we_fence, false);
492    placer.generate_box(3, 3, 4, 3, 4, 4, we_fence, we_fence, false);
493    if *is_needing_chest && placer.clip().contains_blockpos(placer.world_pos(3, 2, 3)) {
494        *is_needing_chest = false;
495        let _ = placer.create_chest(random, 3, 2, 3, NETHER_BRIDGE_LOOT);
496    }
497    placer.generate_box(0, 6, 0, 4, 6, 4, bricks, bricks, false);
498    fill_down_square(placer, 4, 4);
499}
500
501fn place_castle_small_corridor(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
502    let bricks = nether_bricks();
503    let air = air();
504    let ns_fence = fence_ns();
505    placer.generate_box(0, 0, 0, 4, 1, 4, bricks, bricks, false);
506    placer.generate_box(0, 2, 0, 4, 5, 4, air, air, false);
507    placer.generate_box(0, 2, 0, 0, 5, 4, bricks, bricks, false);
508    placer.generate_box(4, 2, 0, 4, 5, 4, bricks, bricks, false);
509    placer.generate_box(0, 3, 1, 0, 4, 1, ns_fence, ns_fence, false);
510    placer.generate_box(0, 3, 3, 0, 4, 3, ns_fence, ns_fence, false);
511    placer.generate_box(4, 3, 1, 4, 4, 1, ns_fence, ns_fence, false);
512    placer.generate_box(4, 3, 3, 4, 4, 3, ns_fence, ns_fence, false);
513    placer.generate_box(0, 6, 0, 4, 6, 4, bricks, bricks, false);
514    fill_down_square(placer, 4, 4);
515}
516
517fn place_castle_small_corridor_right_turn(
518    placer: &mut ScatteredFeaturePlacer<'_, '_>,
519    random: &mut WorldgenRandom,
520    is_needing_chest: &mut bool,
521) {
522    let bricks = nether_bricks();
523    let air = air();
524    let we_fence = fence_we();
525    let ns_fence = fence_ns();
526    placer.generate_box(0, 0, 0, 4, 1, 4, bricks, bricks, false);
527    placer.generate_box(0, 2, 0, 4, 5, 4, air, air, false);
528    placer.generate_box(0, 2, 0, 0, 5, 4, bricks, bricks, false);
529    placer.generate_box(0, 3, 1, 0, 4, 1, ns_fence, ns_fence, false);
530    placer.generate_box(0, 3, 3, 0, 4, 3, ns_fence, ns_fence, false);
531    placer.generate_box(4, 2, 0, 4, 5, 0, bricks, bricks, false);
532    placer.generate_box(1, 2, 4, 4, 5, 4, bricks, bricks, false);
533    placer.generate_box(1, 3, 4, 1, 4, 4, we_fence, we_fence, false);
534    placer.generate_box(3, 3, 4, 3, 4, 4, we_fence, we_fence, false);
535    if *is_needing_chest && placer.clip().contains_blockpos(placer.world_pos(1, 2, 3)) {
536        *is_needing_chest = false;
537        let _ = placer.create_chest(random, 1, 2, 3, NETHER_BRIDGE_LOOT);
538    }
539    placer.generate_box(0, 6, 0, 4, 6, 4, bricks, bricks, false);
540    fill_down_square(placer, 4, 4);
541}
542
543#[expect(
544    clippy::too_many_lines,
545    reason = "straight transcription of vanilla NetherFortressPieces.CastleStalkRoom"
546)]
547fn place_castle_stalk_room(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
548    let bricks = nether_bricks();
549    let air = air();
550    let we_fence = fence_we();
551    let ns_fence = fence_ns();
552    let north_south_west_fence = fence(FENCE_NORTH | FENCE_SOUTH | FENCE_WEST);
553    let north_south_east_fence = fence(FENCE_NORTH | FENCE_SOUTH | FENCE_EAST);
554    placer.generate_box(0, 3, 0, 12, 4, 12, bricks, bricks, false);
555    placer.generate_box(0, 5, 0, 12, 13, 12, air, air, false);
556    placer.generate_box(0, 5, 0, 1, 12, 12, bricks, bricks, false);
557    placer.generate_box(11, 5, 0, 12, 12, 12, bricks, bricks, false);
558    placer.generate_box(2, 5, 11, 4, 12, 12, bricks, bricks, false);
559    placer.generate_box(8, 5, 11, 10, 12, 12, bricks, bricks, false);
560    placer.generate_box(5, 9, 11, 7, 12, 12, bricks, bricks, false);
561    placer.generate_box(2, 5, 0, 4, 12, 1, bricks, bricks, false);
562    placer.generate_box(8, 5, 0, 10, 12, 1, bricks, bricks, false);
563    placer.generate_box(5, 9, 0, 7, 12, 1, bricks, bricks, false);
564    placer.generate_box(2, 11, 2, 10, 12, 10, bricks, bricks, false);
565
566    for i in (1..=11).step_by(2) {
567        placer.generate_box(i, 10, 0, i, 11, 0, we_fence, we_fence, false);
568        placer.generate_box(i, 10, 12, i, 11, 12, we_fence, we_fence, false);
569        placer.generate_box(0, 10, i, 0, 11, i, ns_fence, ns_fence, false);
570        placer.generate_box(12, 10, i, 12, 11, i, ns_fence, ns_fence, false);
571        placer.place_block(bricks, i, 13, 0);
572        placer.place_block(bricks, i, 13, 12);
573        placer.place_block(bricks, 0, 13, i);
574        placer.place_block(bricks, 12, 13, i);
575        if i != 11 {
576            placer.place_block(we_fence, i + 1, 13, 0);
577            placer.place_block(we_fence, i + 1, 13, 12);
578            placer.place_block(ns_fence, 0, 13, i + 1);
579            placer.place_block(ns_fence, 12, 13, i + 1);
580        }
581    }
582
583    placer.place_block(fence(FENCE_NORTH | FENCE_EAST), 0, 13, 0);
584    placer.place_block(fence(FENCE_EAST | FENCE_SOUTH), 0, 13, 12);
585    placer.place_block(fence(FENCE_SOUTH | FENCE_WEST), 12, 13, 12);
586    placer.place_block(fence(FENCE_NORTH | FENCE_WEST), 12, 13, 0);
587
588    for z in (3..=9).step_by(2) {
589        placer.generate_box(
590            1,
591            7,
592            z,
593            1,
594            8,
595            z,
596            north_south_west_fence,
597            north_south_west_fence,
598            false,
599        );
600        placer.generate_box(
601            11,
602            7,
603            z,
604            11,
605            8,
606            z,
607            north_south_east_fence,
608            north_south_east_fence,
609            false,
610        );
611    }
612
613    let north_stairs = stairs(Direction::North);
614    for ix in 0..=6 {
615        let z = ix + 4;
616        for x in 5..=7 {
617            placer.place_block(north_stairs, x, 5 + ix, z);
618        }
619
620        if (5..=8).contains(&z) {
621            placer.generate_box(5, 5, z, 7, ix + 4, z, bricks, bricks, false);
622        } else if (9..=10).contains(&z) {
623            placer.generate_box(5, 8, z, 7, ix + 4, z, bricks, bricks, false);
624        }
625
626        if ix >= 1 {
627            placer.generate_box(5, 6 + ix, z, 7, 9 + ix, z, air, air, false);
628        }
629    }
630
631    for x in 5..=7 {
632        placer.place_block(north_stairs, x, 12, 11);
633    }
634
635    placer.generate_box(
636        5,
637        6,
638        7,
639        5,
640        7,
641        7,
642        north_south_east_fence,
643        north_south_east_fence,
644        false,
645    );
646    placer.generate_box(
647        7,
648        6,
649        7,
650        7,
651        7,
652        7,
653        north_south_west_fence,
654        north_south_west_fence,
655        false,
656    );
657    placer.generate_box(5, 13, 12, 7, 13, 12, air, air, false);
658    placer.generate_box(2, 5, 2, 3, 5, 3, bricks, bricks, false);
659    placer.generate_box(2, 5, 9, 3, 5, 10, bricks, bricks, false);
660    placer.generate_box(2, 5, 4, 2, 5, 8, bricks, bricks, false);
661    placer.generate_box(9, 5, 2, 10, 5, 3, bricks, bricks, false);
662    placer.generate_box(9, 5, 9, 10, 5, 10, bricks, bricks, false);
663    placer.generate_box(10, 5, 4, 10, 5, 8, bricks, bricks, false);
664    let east_stairs = stairs(Direction::East);
665    let west_stairs = stairs(Direction::West);
666    placer.place_block(west_stairs, 4, 5, 2);
667    placer.place_block(west_stairs, 4, 5, 3);
668    placer.place_block(west_stairs, 4, 5, 9);
669    placer.place_block(west_stairs, 4, 5, 10);
670    placer.place_block(east_stairs, 8, 5, 2);
671    placer.place_block(east_stairs, 8, 5, 3);
672    placer.place_block(east_stairs, 8, 5, 9);
673    placer.place_block(east_stairs, 8, 5, 10);
674    placer.generate_box(3, 4, 4, 4, 4, 8, soul_sand(), soul_sand(), false);
675    placer.generate_box(8, 4, 4, 9, 4, 8, soul_sand(), soul_sand(), false);
676    placer.generate_box(3, 5, 4, 4, 5, 8, nether_wart(), nether_wart(), false);
677    placer.generate_box(8, 5, 4, 9, 5, 8, nether_wart(), nether_wart(), false);
678    place_castle_cross_foundation(placer);
679}
680
681fn place_monster_throne(
682    placer: &mut ScatteredFeaturePlacer<'_, '_>,
683    has_placed_spawner: &mut bool,
684) {
685    let bricks = nether_bricks();
686    let air = air();
687    let we_fence = fence_we();
688    let ns_fence = fence_ns();
689    placer.generate_box(0, 2, 0, 6, 7, 7, air, air, false);
690    placer.generate_box(1, 0, 0, 5, 1, 7, bricks, bricks, false);
691    placer.generate_box(1, 2, 1, 5, 2, 7, bricks, bricks, false);
692    placer.generate_box(1, 3, 2, 5, 3, 7, bricks, bricks, false);
693    placer.generate_box(1, 4, 3, 5, 4, 7, bricks, bricks, false);
694    placer.generate_box(1, 2, 0, 1, 4, 2, bricks, bricks, false);
695    placer.generate_box(5, 2, 0, 5, 4, 2, bricks, bricks, false);
696    placer.generate_box(1, 5, 2, 1, 5, 3, bricks, bricks, false);
697    placer.generate_box(5, 5, 2, 5, 5, 3, bricks, bricks, false);
698    placer.generate_box(0, 5, 3, 0, 5, 8, bricks, bricks, false);
699    placer.generate_box(6, 5, 3, 6, 5, 8, bricks, bricks, false);
700    placer.generate_box(1, 5, 8, 5, 5, 8, bricks, bricks, false);
701    placer.place_block(fence(FENCE_WEST), 1, 6, 3);
702    placer.place_block(fence(FENCE_EAST), 5, 6, 3);
703    placer.place_block(fence(FENCE_NORTH | FENCE_EAST), 0, 6, 3);
704    placer.place_block(fence(FENCE_NORTH | FENCE_WEST), 6, 6, 3);
705    placer.generate_box(0, 6, 4, 0, 6, 7, ns_fence, ns_fence, false);
706    placer.generate_box(6, 6, 4, 6, 6, 7, ns_fence, ns_fence, false);
707    placer.place_block(fence(FENCE_EAST | FENCE_SOUTH), 0, 6, 8);
708    placer.place_block(fence(FENCE_SOUTH | FENCE_WEST), 6, 6, 8);
709    placer.generate_box(1, 6, 8, 5, 6, 8, we_fence, we_fence, false);
710    placer.place_block(fence(FENCE_EAST), 1, 7, 8);
711    placer.generate_box(2, 7, 8, 4, 7, 8, we_fence, we_fence, false);
712    placer.place_block(fence(FENCE_WEST), 5, 7, 8);
713    placer.place_block(fence(FENCE_EAST), 2, 8, 8);
714    placer.place_block(we_fence, 3, 8, 8);
715    placer.place_block(fence(FENCE_WEST), 4, 8, 8);
716    if !*has_placed_spawner && placer.clip().contains_blockpos(placer.world_pos(3, 5, 5)) {
717        *has_placed_spawner = true;
718        let _ = placer.create_spawner(3, 5, 5, BLAZE_ENTITY);
719    }
720
721    for x in 0..=6 {
722        for z in 0..=6 {
723            placer.fill_column_down(bricks, x, -1, z);
724        }
725    }
726}
727
728fn place_room_crossing(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
729    let bricks = nether_bricks();
730    let air = air();
731    let we_fence = fence_we();
732    let ns_fence = fence_ns();
733    placer.generate_box(0, 0, 0, 6, 1, 6, bricks, bricks, false);
734    placer.generate_box(0, 2, 0, 6, 7, 6, air, air, false);
735    placer.generate_box(0, 2, 0, 1, 6, 0, bricks, bricks, false);
736    placer.generate_box(0, 2, 6, 1, 6, 6, bricks, bricks, false);
737    placer.generate_box(5, 2, 0, 6, 6, 0, bricks, bricks, false);
738    placer.generate_box(5, 2, 6, 6, 6, 6, bricks, bricks, false);
739    placer.generate_box(0, 2, 0, 0, 6, 1, bricks, bricks, false);
740    placer.generate_box(0, 2, 5, 0, 6, 6, bricks, bricks, false);
741    placer.generate_box(6, 2, 0, 6, 6, 1, bricks, bricks, false);
742    placer.generate_box(6, 2, 5, 6, 6, 6, bricks, bricks, false);
743    placer.generate_box(2, 6, 0, 4, 6, 0, bricks, bricks, false);
744    placer.generate_box(2, 5, 0, 4, 5, 0, we_fence, we_fence, false);
745    placer.generate_box(2, 6, 6, 4, 6, 6, bricks, bricks, false);
746    placer.generate_box(2, 5, 6, 4, 5, 6, we_fence, we_fence, false);
747    placer.generate_box(0, 6, 2, 0, 6, 4, bricks, bricks, false);
748    placer.generate_box(0, 5, 2, 0, 5, 4, ns_fence, ns_fence, false);
749    placer.generate_box(6, 6, 2, 6, 6, 4, bricks, bricks, false);
750    placer.generate_box(6, 5, 2, 6, 5, 4, ns_fence, ns_fence, false);
751    fill_down_square(placer, 6, 6);
752}
753
754fn place_stairs_room(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
755    let bricks = nether_bricks();
756    let air = air();
757    let we_fence = fence_we();
758    let ns_fence = fence_ns();
759    placer.generate_box(0, 0, 0, 6, 1, 6, bricks, bricks, false);
760    placer.generate_box(0, 2, 0, 6, 10, 6, air, air, false);
761    placer.generate_box(0, 2, 0, 1, 8, 0, bricks, bricks, false);
762    placer.generate_box(5, 2, 0, 6, 8, 0, bricks, bricks, false);
763    placer.generate_box(0, 2, 1, 0, 8, 6, bricks, bricks, false);
764    placer.generate_box(6, 2, 1, 6, 8, 6, bricks, bricks, false);
765    placer.generate_box(1, 2, 6, 5, 8, 6, bricks, bricks, false);
766    placer.generate_box(0, 3, 2, 0, 5, 4, ns_fence, ns_fence, false);
767    placer.generate_box(6, 3, 2, 6, 5, 2, ns_fence, ns_fence, false);
768    placer.generate_box(6, 3, 4, 6, 5, 4, ns_fence, ns_fence, false);
769    placer.place_block(bricks, 5, 2, 5);
770    placer.generate_box(4, 2, 5, 4, 3, 5, bricks, bricks, false);
771    placer.generate_box(3, 2, 5, 3, 4, 5, bricks, bricks, false);
772    placer.generate_box(2, 2, 5, 2, 5, 5, bricks, bricks, false);
773    placer.generate_box(1, 2, 5, 1, 6, 5, bricks, bricks, false);
774    placer.generate_box(1, 7, 1, 5, 7, 4, bricks, bricks, false);
775    placer.generate_box(6, 8, 2, 6, 8, 4, air, air, false);
776    placer.generate_box(2, 6, 0, 4, 8, 0, bricks, bricks, false);
777    placer.generate_box(2, 5, 0, 4, 5, 0, we_fence, we_fence, false);
778    fill_down_square(placer, 6, 6);
779}
780
781fn place_castle_cross_foundation(placer: &mut ScatteredFeaturePlacer<'_, '_>) {
782    let bricks = nether_bricks();
783    placer.generate_box(4, 2, 0, 8, 2, 12, bricks, bricks, false);
784    placer.generate_box(0, 2, 4, 12, 2, 8, bricks, bricks, false);
785    placer.generate_box(4, 0, 0, 8, 1, 3, bricks, bricks, false);
786    placer.generate_box(4, 0, 9, 8, 1, 12, bricks, bricks, false);
787    placer.generate_box(0, 0, 4, 3, 1, 8, bricks, bricks, false);
788    placer.generate_box(9, 0, 4, 12, 1, 8, bricks, bricks, false);
789
790    for x in 4..=8 {
791        for z in 0..=2 {
792            placer.fill_column_down(bricks, x, -1, z);
793            placer.fill_column_down(bricks, x, -1, 12 - z);
794        }
795    }
796
797    for x in 0..=2 {
798        for z in 4..=8 {
799            placer.fill_column_down(bricks, x, -1, z);
800            placer.fill_column_down(bricks, 12 - x, -1, z);
801        }
802    }
803}
804
805fn fill_down_square(placer: &mut ScatteredFeaturePlacer<'_, '_>, max_x: i32, max_z: i32) {
806    let bricks = nether_bricks();
807    for x in 0..=max_x {
808        for z in 0..=max_z {
809            placer.fill_column_down(bricks, x, -1, z);
810        }
811    }
812}