93 lines
3.1 KiB
Rust
93 lines
3.1 KiB
Rust
use pumpkin_data::item::Item;
|
|
use std::sync::Arc;
|
|
|
|
use crate::block::registry::BlockActionResult;
|
|
use crate::block::{
|
|
BlockBehaviour, BlockFuture, ExplodeArgs, OnNeighborUpdateArgs, PlacedArgs, UseWithItemArgs,
|
|
};
|
|
use crate::entity::Entity;
|
|
use crate::entity::tnt::TNTEntity;
|
|
use crate::world::World;
|
|
use pumpkin_data::BlockStateId;
|
|
use pumpkin_data::entity::EntityType;
|
|
use pumpkin_data::sound::SoundCategory;
|
|
use pumpkin_macros::pumpkin_block;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_util::math::vector3::Vector3;
|
|
use pumpkin_world::world::BlockFlags;
|
|
use rand::RngExt;
|
|
|
|
use super::redstone::block_receives_redstone_power;
|
|
|
|
#[pumpkin_block("minecraft:tnt")]
|
|
pub struct TNTBlock;
|
|
|
|
impl TNTBlock {
|
|
pub async fn prime(world: &Arc<World>, location: &BlockPos) {
|
|
let entity = Entity::new(world.clone(), location.to_f64(), &EntityType::TNT);
|
|
let pos = entity.pos.load();
|
|
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, DEFAULT_FUSE));
|
|
world.spawn_entity(tnt).await;
|
|
world.play_sound(
|
|
pumpkin_data::sound::Sound::EntityTntPrimed,
|
|
SoundCategory::Blocks,
|
|
&pos,
|
|
);
|
|
world
|
|
.set_block_state(location, BlockStateId::AIR, BlockFlags::NOTIFY_ALL)
|
|
.await;
|
|
}
|
|
}
|
|
|
|
const DEFAULT_FUSE: u32 = 80;
|
|
const DEFAULT_POWER: f32 = 4.0;
|
|
|
|
impl BlockBehaviour for TNTBlock {
|
|
fn use_with_item<'a>(
|
|
&'a self,
|
|
args: UseWithItemArgs<'a>,
|
|
) -> BlockFuture<'a, BlockActionResult> {
|
|
Box::pin(async move {
|
|
let item = args.item_stack.lock().await.item;
|
|
if item != &Item::FLINT_AND_STEEL || item == &Item::FIRE_CHARGE {
|
|
return BlockActionResult::Pass;
|
|
}
|
|
let world = args.player.world();
|
|
Self::prime(&world, args.position).await;
|
|
|
|
BlockActionResult::Consume
|
|
})
|
|
}
|
|
|
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
if block_receives_redstone_power(args.world, args.position).await {
|
|
Self::prime(args.world, args.position).await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
if block_receives_redstone_power(args.world, args.position).await {
|
|
Self::prime(args.world, args.position).await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn explode<'a>(&'a self, args: ExplodeArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
let entity = Entity::new(args.world.clone(), args.position.to_f64(), &EntityType::TNT);
|
|
let angle = rand::random::<f64>() * std::f64::consts::TAU;
|
|
entity.set_velocity(Vector3::new(-angle.sin() * 0.02, 0.2, -angle.cos() * 0.02));
|
|
let fuse = rand::rng().random_range(0..DEFAULT_FUSE / 4) + DEFAULT_FUSE / 8;
|
|
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, fuse));
|
|
args.world.spawn_entity(tnt).await;
|
|
})
|
|
}
|
|
|
|
fn should_drop_items_on_explosion(&self) -> bool {
|
|
false
|
|
}
|
|
}
|