steel_core/behavior/items/
snowball.rs1use std::sync::Arc;
8
9use steel_macros::item_behavior;
10use steel_protocol::packets::game::SoundSource;
11use steel_registry::stat::vanilla_stat_types;
12use steel_registry::{sound_events, vanilla_entities};
13
14use crate::behavior::context::{InteractionResult, UseItemContext};
15use crate::behavior::item::ItemBehavior;
16use crate::entity::entities::SnowballEntity;
17use crate::entity::{Entity, next_entity_id, spawn_throwable_item_projectile};
18
19const SHOOT_POWER: f32 = 1.5;
21const THROW_SOUND_VOLUME: f32 = 0.5;
23const THROW_PITCH_JITTER_SCALE: f32 = 0.4;
25const THROW_PITCH_JITTER_BASE: f32 = 0.8;
27const THROW_UNCERTAINTY: f32 = 1.0;
29
30#[item_behavior(class = "SnowballItem")]
32pub struct SnowballItem;
33
34impl ItemBehavior for SnowballItem {
35 fn use_item(&self, context: &mut UseItemContext) -> InteractionResult {
36 let player = context.player;
37 let world = context.world;
38
39 let pitch = THROW_PITCH_JITTER_SCALE
40 / rand::random_range(
41 THROW_PITCH_JITTER_BASE..THROW_PITCH_JITTER_BASE + THROW_PITCH_JITTER_SCALE,
42 );
43 world.play_sound_at(
44 &sound_events::ENTITY_SNOWBALL_THROW,
45 SoundSource::Neutral,
46 player.position(),
47 THROW_SOUND_VOLUME,
48 pitch,
49 None,
50 );
51
52 let mut thrown_item = context.inv.with_item(|item| item.clone());
53 let Some(_snowball) = spawn_throwable_item_projectile(
54 world,
55 player,
56 &mut thrown_item,
57 SHOOT_POWER,
58 THROW_UNCERTAINTY,
59 |spawn_pos| {
60 SnowballEntity::new(
61 &vanilla_entities::SNOWBALL,
62 next_entity_id(),
63 spawn_pos,
64 Arc::downgrade(world),
65 )
66 },
67 ) else {
68 return InteractionResult::Fail;
69 };
70
71 player.award_stat(&vanilla_stat_types::ITEM_USED, thrown_item.item);
72 let has_infinite_materials = player.has_infinite_materials();
73 context
74 .inv
75 .with_item(|item| item.consume_one(has_infinite_materials));
76
77 InteractionResult::Success
78 }
79}