Skip to main content

steel_core/behavior/items/
axe.rs

1use steel_macros::item_behavior;
2use steel_registry::{
3    REGISTRY,
4    blocks::{
5        block_state_ext::BlockStateExt,
6        properties::{BlockStateProperties, EnumProperty},
7    },
8    data_components::vanilla_components::BLOCKS_ATTACKS,
9    level_events::{PARTICLES_SCRAPE, PARTICLES_WAX_OFF},
10    sound_events::{ITEM_AXE_SCRAPE, ITEM_AXE_STRIP, ITEM_AXE_WAX_OFF},
11    vanilla_game_events,
12};
13use steel_utils::{
14    axis::Axis,
15    types::{InteractionHand, UpdateFlags},
16};
17
18use crate::{
19    behavior::{
20        InteractionResult, ItemBehavior, UseOnContext, strippables::get_strippable_variant,
21        waxables::get_normal_from_waxed_variant, weathering::previous_copper_stage,
22    },
23    entity::Entity,
24    world::game_event::GameEventContext,
25};
26
27use super::copper_chest_events::emit_connected_chest_block_change;
28
29const AXIS_PROPERTY: EnumProperty<Axis> = BlockStateProperties::AXIS;
30
31/// Behavior for Axes, when used on wood or logs it turns them into their stripped variants
32#[item_behavior]
33pub struct AxeItem;
34
35impl ItemBehavior for AxeItem {
36    fn use_on(&self, context: &mut UseOnContext) -> InteractionResult {
37        let has_block_item_intent = context.hand == InteractionHand::MainHand
38            && context
39                .inv
40                .with_inventory(|inv| inv.get_offhand_item().has(BLOCKS_ATTACKS))
41            && !context.player.is_secondary_use_active();
42
43        if has_block_item_intent {
44            return InteractionResult::Pass;
45        }
46
47        let old_block_state = context.world.get_block_state(context.hit_result.block_pos);
48        let old_block = old_block_state.get_block();
49
50        let pos = context.hit_result.block_pos;
51
52        let (new_block_state, sound_event, level_event) =
53            if let Some(new_block) = get_strippable_variant(old_block) {
54                let old_axis = old_block_state.get_value(&AXIS_PROPERTY);
55                let new_block_state = new_block
56                    .default_state()
57                    .set_value(&AXIS_PROPERTY, old_axis);
58
59                (new_block_state, &ITEM_AXE_STRIP, None)
60            } else if let Some(scraped_block) = previous_copper_stage(old_block) {
61                let new_block_state = REGISTRY
62                    .blocks
63                    .copy_matching_properties(old_block_state, scraped_block);
64
65                (new_block_state, &ITEM_AXE_SCRAPE, Some(PARTICLES_SCRAPE))
66            } else if let Some(unwaxed_block) = get_normal_from_waxed_variant(old_block) {
67                let new_block_state = REGISTRY
68                    .blocks
69                    .copy_matching_properties(old_block_state, unwaxed_block);
70
71                (new_block_state, &ITEM_AXE_WAX_OFF, Some(PARTICLES_WAX_OFF))
72            } else {
73                return InteractionResult::Pass;
74            };
75
76        context
77            .world
78            .set_block(pos, new_block_state, UpdateFlags::UPDATE_ALL_IMMEDIATE);
79
80        context
81            .world
82            .play_block_sound(sound_event, pos, 1.0, 1.0, Some(context.player.id()));
83
84        if let Some(event) = level_event {
85            context
86                .world
87                .level_event(event, pos, 0, Some(context.player.id()));
88            emit_connected_chest_block_change(
89                context.world,
90                pos,
91                old_block_state,
92                context.player,
93                Some(event),
94            );
95        }
96
97        context.world.game_event(
98            &vanilla_game_events::BLOCK_CHANGE,
99            pos,
100            &GameEventContext::new(Some(context.player), Some(new_block_state)),
101        );
102
103        let has_infinite_materials = context.player.has_infinite_materials();
104        context
105            .inv
106            .with_item(|item| item.hurt_and_break(1, has_infinite_materials));
107
108        InteractionResult::Success
109    }
110}