azalea_entity/
mining.rs

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