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}