azalea_entity/
mining.rs

1use azalea_block::{BlockBehavior, BlockTrait};
2use azalea_core::tier::get_item_tier;
3use azalea_registry as registry;
4
5use crate::{FluidOnEyes, Physics, effects};
6
7/// How much progress is made towards mining the block per tick, as a
8/// percentage.
9///
10/// If this is 1, then the block gets broken instantly.
11///
12/// You can divide 1 by this and then round up to get the number of ticks it
13/// takes to mine the block.
14///
15/// The player inventory is needed to check your armor and offhand for modifiers
16/// to your mining speed.
17pub fn get_mine_progress(
18    block: &dyn BlockTrait,
19    held_item: registry::Item,
20    player_inventory: &azalea_inventory::Menu,
21    fluid_on_eyes: &FluidOnEyes,
22    physics: &Physics,
23) -> f32 {
24    let block_behavior: BlockBehavior = block.behavior();
25
26    let destroy_time = block_behavior.destroy_time;
27    if destroy_time == -1. {
28        return 0.;
29    }
30    let divisor = if has_correct_tool_for_drops(block, held_item) {
31        30
32    } else {
33        100
34    };
35
36    let base_destroy_speed = destroy_speed(
37        block.as_registry_block(),
38        held_item,
39        player_inventory,
40        fluid_on_eyes,
41        physics,
42    );
43    (base_destroy_speed / destroy_time) / divisor as f32
44}
45
46fn has_correct_tool_for_drops(block: &dyn BlockTrait, tool: registry::Item) -> bool {
47    if !block.behavior().requires_correct_tool_for_drops {
48        return true;
49    }
50    let registry_block = block.as_registry_block();
51    if tool == registry::Item::Shears {
52        matches!(
53            registry_block,
54            registry::Block::Cobweb | registry::Block::RedstoneWire | registry::Block::Tripwire
55        )
56    } else if registry::tags::items::SWORDS.contains(&tool) {
57        registry_block == registry::Block::Cobweb
58    } else if registry::tags::items::PICKAXES.contains(&tool)
59        || registry::tags::items::SHOVELS.contains(&tool)
60        || registry::tags::items::HOES.contains(&tool)
61        || registry::tags::items::AXES.contains(&tool)
62    {
63        let tier = get_item_tier(tool).expect("all pickaxes and shovels should be matched");
64        let tier_level = tier.level();
65        !((tier_level < 3 && registry::tags::blocks::NEEDS_DIAMOND_TOOL.contains(&registry_block))
66            || (tier_level < 2
67                && registry::tags::blocks::NEEDS_IRON_TOOL.contains(&registry_block))
68            || (tier_level < 1
69                && registry::tags::blocks::NEEDS_STONE_TOOL.contains(&registry_block)))
70    } else {
71        false
72    }
73}
74
75/// Returns the destroy speed of the given block with the given tool, taking
76/// enchantments and effects into account.
77///
78/// If the player is not holding anything, then `tool` should be `Item::Air`.
79fn destroy_speed(
80    block: registry::Block,
81    tool: registry::Item,
82    _player_inventory: &azalea_inventory::Menu,
83    _fluid_on_eyes: &FluidOnEyes,
84    physics: &Physics,
85) -> f32 {
86    let mut base_destroy_speed = base_destroy_speed(block, tool);
87
88    // add efficiency enchantment
89    // TODO
90    // if base_destroy_speed > 1. {
91    //     let efficiency_level =
92    //         enchantments::get_enchant_level(registry::Enchantment::Efficiency,
93    // player_inventory);     if efficiency_level > 0 && tool !=
94    // registry::Item::Air {         base_destroy_speed += (efficiency_level *
95    // efficiency_level + 1) as f32;     }
96    // }
97
98    if let Some(dig_speed_amplifier) = 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) = effects::get_effect(registry::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    // TODO
113    // if **fluid_on_eyes == FluidKind::Water
114    //     && enchantments::get_enchant_level(registry::Enchantment::AquaAffinity,
115    // player_inventory)         == 0
116    // {
117    //     base_destroy_speed /= 5.;
118    // }
119
120    if !physics.on_ground {
121        base_destroy_speed /= 5.;
122    }
123
124    base_destroy_speed
125}
126
127fn base_destroy_speed(block: registry::Block, tool: registry::Item) -> f32 {
128    if tool == registry::Item::Shears {
129        if block == registry::Block::Cobweb || registry::tags::blocks::LEAVES.contains(&block) {
130            15.
131        } else if registry::tags::blocks::WOOL.contains(&block) {
132            5.
133        } else if matches!(block, registry::Block::Vine | registry::Block::GlowLichen) {
134            2.
135        } else {
136            1.
137        }
138    } else if registry::tags::items::SWORDS.contains(&tool) {
139        if block == registry::Block::Cobweb {
140            15.
141        } else if registry::tags::blocks::SWORD_EFFICIENT.contains(&block) {
142            1.5
143        } else {
144            1.
145        }
146    } else if registry::tags::items::PICKAXES.contains(&tool) {
147        if registry::tags::blocks::MINEABLE_PICKAXE.contains(&block) {
148            get_item_tier(tool).unwrap().speed()
149        } else {
150            1.
151        }
152    } else if registry::tags::items::SHOVELS.contains(&tool) {
153        if registry::tags::blocks::MINEABLE_SHOVEL.contains(&block) {
154            get_item_tier(tool).unwrap().speed()
155        } else {
156            1.
157        }
158    } else if registry::tags::items::HOES.contains(&tool) {
159        if registry::tags::blocks::MINEABLE_HOE.contains(&block) {
160            get_item_tier(tool).unwrap().speed()
161        } else {
162            1.
163        }
164    } else if registry::tags::items::AXES.contains(&tool) {
165        if registry::tags::blocks::MINEABLE_AXE.contains(&block) {
166            get_item_tier(tool).unwrap().speed()
167        } else {
168            1.
169        }
170    } else {
171        1.
172    }
173}