steel_core/behavior/items/
hoe.rs1use steel_macros::item_behavior;
2use steel_registry::{
3 blocks::{BlockRef, block_state_ext::BlockStateExt},
4 item_stack::ItemStack,
5 sound_events, vanilla_blocks, vanilla_game_events, vanilla_items,
6};
7use steel_utils::{Direction, types::UpdateFlags};
8
9use crate::{
10 behavior::{InteractionResult, ItemBehavior, UseOnContext},
11 entity::Entity,
12 world::game_event::GameEventContext,
13};
14
15#[item_behavior]
17pub struct HoeItem;
18
19impl HoeItem {
20 fn get_tilled_variant(block: BlockRef) -> Option<BlockRef> {
21 match block {
22 _ if block == &vanilla_blocks::GRASS_BLOCK
23 || block == &vanilla_blocks::DIRT_PATH
24 || block == &vanilla_blocks::DIRT =>
25 {
26 Some(&vanilla_blocks::FARMLAND)
27 }
28 _ if block == &vanilla_blocks::COARSE_DIRT => Some(&vanilla_blocks::DIRT),
29 _ if block == &vanilla_blocks::ROOTED_DIRT => Some(&vanilla_blocks::DIRT),
30 _ => None,
31 }
32 }
33}
34
35impl ItemBehavior for HoeItem {
36 fn use_on(&self, context: &mut UseOnContext) -> InteractionResult {
37 let state = context.world.get_block_state(context.hit_result.block_pos);
38 let Some(tilled_variant) = Self::get_tilled_variant(state.get_block()) else {
39 return InteractionResult::Pass;
40 };
41
42 if (context.hit_result.direction == Direction::Down
43 || !context
44 .world
45 .get_block_state(context.hit_result.block_pos.above())
46 .is_air())
47 && state.get_block() != &vanilla_blocks::ROOTED_DIRT
48 {
49 return InteractionResult::Pass;
50 }
51
52 let new_state = tilled_variant.default_state();
53 context.world.set_block(
54 context.hit_result.block_pos,
55 new_state,
56 UpdateFlags::UPDATE_ALL_IMMEDIATE,
57 );
58 context.world.game_event(
59 &vanilla_game_events::BLOCK_CHANGE,
60 context.hit_result.block_pos,
61 &GameEventContext::new(Some(context.player), Some(new_state)),
62 );
63
64 if state.get_block() == &vanilla_blocks::ROOTED_DIRT {
65 context.world.pop_resource_from_face(
66 context.hit_result.block_pos,
67 context.hit_result.direction,
68 ItemStack::new(&vanilla_items::HANGING_ROOTS),
69 );
70 }
71
72 context.world.play_block_sound(
73 &sound_events::ITEM_HOE_TILL,
74 context.hit_result.block_pos,
75 1.0,
76 1.0,
77 Some(context.player.id()),
78 );
79
80 let has_infinite_materials = context.player.has_infinite_materials();
81 context
82 .inv
83 .with_item(|item| item.hurt_and_break(1, has_infinite_materials));
84
85 InteractionResult::Success
86 }
87}