1use azalea_block::{BlockBehavior, BlockTrait};
2use azalea_core::tier::get_item_tier;
3use azalea_registry::{
4 builtin::{BlockKind, ItemKind, MobEffect},
5 tags,
6};
7
8use crate::{ActiveEffects, Attributes, FluidOnEyes, Physics};
9
10pub fn get_mine_progress(
21 block: &dyn BlockTrait,
22 held_item: ItemKind,
23 fluid_on_eyes: &FluidOnEyes,
24 physics: &Physics,
25 attributes: &Attributes,
26 active_effects: &ActiveEffects,
27) -> f32 {
28 let block_behavior: BlockBehavior = block.behavior();
29
30 let destroy_time = block_behavior.destroy_time;
31 if destroy_time == -1. {
32 return 0.;
33 }
34 let divisor = if has_correct_tool_for_drops(block, held_item) {
35 30
36 } else {
37 100
38 };
39
40 let base_destroy_speed = destroy_speed(
41 block.as_registry_block(),
42 held_item,
43 fluid_on_eyes,
44 physics,
45 attributes,
46 active_effects,
47 );
48 (base_destroy_speed / destroy_time) / divisor as f32
49}
50
51fn has_correct_tool_for_drops(block: &dyn BlockTrait, tool: ItemKind) -> bool {
52 if !block.behavior().requires_correct_tool_for_drops {
53 return true;
54 }
55 let registry_block = block.as_registry_block();
56 if tool == ItemKind::Shears {
57 matches!(
58 registry_block,
59 BlockKind::Cobweb | BlockKind::RedstoneWire | BlockKind::Tripwire
60 )
61 } else if tags::items::SWORDS.contains(&tool) {
62 registry_block == BlockKind::Cobweb
63 } else if tags::items::PICKAXES.contains(&tool)
64 || tags::items::SHOVELS.contains(&tool)
65 || tags::items::HOES.contains(&tool)
66 || tags::items::AXES.contains(&tool)
67 {
68 let tier = get_item_tier(tool).expect("all pickaxes and shovels should be matched");
69 let tier_level = tier.level();
70 !((tier_level < 3 && tags::blocks::NEEDS_DIAMOND_TOOL.contains(®istry_block))
71 || (tier_level < 2 && tags::blocks::NEEDS_IRON_TOOL.contains(®istry_block))
72 || (tier_level < 1 && tags::blocks::NEEDS_STONE_TOOL.contains(®istry_block)))
73 } else {
74 false
75 }
76}
77
78fn destroy_speed(
84 block: BlockKind,
85 tool: ItemKind,
86 _fluid_on_eyes: &FluidOnEyes,
87 physics: &Physics,
88 attributes: &Attributes,
89 active_effects: &ActiveEffects,
90) -> f32 {
91 let mut base_destroy_speed = base_destroy_speed(block, tool);
92
93 if base_destroy_speed > 1. {
94 base_destroy_speed += attributes.mining_efficiency.calculate() as f32;
96 }
97
98 if let Some(dig_speed_amplifier) = active_effects.get_dig_speed_amplifier() {
99 base_destroy_speed *= 1. + (dig_speed_amplifier + 1) as f32 * 0.2;
100 }
101
102 if let Some(dig_slowdown) = active_effects.get_level(MobEffect::MiningFatigue) {
103 let multiplier = match dig_slowdown {
104 0 => 0.3,
105 1 => 0.09,
106 2 => 0.0027,
107 _ => 8.1E-4,
108 };
109 base_destroy_speed *= multiplier;
110 }
111
112 if !physics.on_ground {
121 base_destroy_speed /= 5.;
122 }
123
124 base_destroy_speed
125}
126
127fn base_destroy_speed(block: BlockKind, tool: ItemKind) -> f32 {
128 if tool == ItemKind::Shears {
129 if block == BlockKind::Cobweb || tags::blocks::LEAVES.contains(&block) {
130 15.
131 } else if tags::blocks::WOOL.contains(&block) {
132 5.
133 } else if matches!(block, BlockKind::Vine | BlockKind::GlowLichen) {
134 2.
135 } else {
136 1.
137 }
138 } else if tags::items::SWORDS.contains(&tool) {
139 if block == BlockKind::Cobweb {
140 15.
141 } else if tags::blocks::SWORD_EFFICIENT.contains(&block) {
142 1.5
143 } else {
144 1.
145 }
146 } else if tags::items::PICKAXES.contains(&tool) {
147 if tags::blocks::MINEABLE_PICKAXE.contains(&block) {
148 get_item_tier(tool).unwrap().speed()
149 } else {
150 1.
151 }
152 } else if tags::items::SHOVELS.contains(&tool) {
153 if tags::blocks::MINEABLE_SHOVEL.contains(&block) {
154 get_item_tier(tool).unwrap().speed()
155 } else {
156 1.
157 }
158 } else if tags::items::HOES.contains(&tool) {
159 if tags::blocks::MINEABLE_HOE.contains(&block) {
160 get_item_tier(tool).unwrap().speed()
161 } else {
162 1.
163 }
164 } else if tags::items::AXES.contains(&tool) {
165 if tags::blocks::MINEABLE_AXE.contains(&block) {
166 get_item_tier(tool).unwrap().speed()
167 } else {
168 1.
169 }
170 } else {
171 1.
172 }
173}