azalea_entity/
mining.rs

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