Pumpkin/crates/pumpkin/src/block/blocks/wither_skull.rs
2026-08-24 16:00:06 +02:00

100 lines
4.0 KiB
Rust

use pumpkin_data::{Block, BlockDirection, BlockStateId, entity::EntityType, world::WorldEvent};
use pumpkin_macros::pumpkin_block;
use pumpkin_world::world::BlockFlags;
use crate::{
block::{
BlockBehaviour, BlockFuture, OnPlaceArgs, PlacedArgs, blocks::skull_block::SkullBlock,
},
entity::{Entity, boss::wither::WitherEntity},
};
#[pumpkin_block("wither_skeleton_skull")]
pub struct WitherSkeletonSkullBlock;
impl BlockBehaviour for WitherSkeletonSkullBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
SkullBlock::on_place(&SkullBlock, args)
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let entity = crate::block::entities::skull::SkullBlockEntity::new(*args.position);
args.world.add_block_entity(std::sync::Arc::new(entity));
let world = args.world;
let pos = args.position;
let is_soul_block =
|block: &Block| block == &Block::SOUL_SAND || block == &Block::SOUL_SOIL;
let is_skull = |block: &Block| block == &Block::WITHER_SKELETON_SKULL;
for dir in [BlockDirection::North, BlockDirection::West] {
let opposite = dir.opposite();
for offset in 0..3 {
let center_skull_pos = match offset {
0 => *pos,
1 => pos.offset(opposite.to_offset()),
2 => pos.offset(dir.to_offset()),
_ => {
tracing::error!("Invalid offset in wither skull check: {}", offset);
*pos
}
};
let top_middle = center_skull_pos.down();
let base = top_middle.down();
let arm1 = top_middle.offset(dir.to_offset());
let arm2 = top_middle.offset(opposite.to_offset());
let skull1_pos = arm1.up();
let skull2_pos = arm2.up();
if is_soul_block(world.get_block(&top_middle))
&& is_soul_block(world.get_block(&base))
&& is_soul_block(world.get_block(&arm1))
&& is_soul_block(world.get_block(&arm2))
&& is_skull(world.get_block(&center_skull_pos))
&& is_skull(world.get_block(&skull1_pos))
&& is_skull(world.get_block(&skull2_pos))
{
let pattern = [
center_skull_pos,
skull1_pos,
skull2_pos,
top_middle,
arm1,
arm2,
base,
];
for p in pattern {
world
.set_block_state(
&p,
Block::AIR.default_state.id,
BlockFlags::NOTIFY_ALL,
)
.await;
world.sync_world_event(
WorldEvent::ParticlesDestroyBlock,
p,
Block::SOUL_SAND.default_state.id.as_u16().into(),
);
}
let entity = Entity::new(
world.clone(),
top_middle.to_centered_f64(),
&EntityType::WITHER,
);
let wither = WitherEntity::new(entity);
wither.make_invulnerable();
world.spawn_entity(wither).await;
return;
}
}
}
})
}
}