Skip to main content

steel_core/behavior/items/
hoe.rs

1use 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/// Behavior for Hoes
16#[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}