steel_core/behavior/items/
axe.rs1use 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#[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}