veloren_common/comp/body/
item.rs

1use crate::{
2    comp::{
3        Density, Mass, Ori, ThrownItem,
4        item::{
5            Item, ItemKind, Utility,
6            armor::ArmorKind,
7            tool::{Tool, ToolKind},
8        },
9    },
10    consts::WATER_DENSITY,
11    make_case_elim,
12    util::Dir,
13};
14use rand::prelude::*;
15use serde::{Deserialize, Serialize};
16use std::f32::consts::PI;
17use vek::Vec3;
18
19make_case_elim!(
20    armor,
21    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
22    #[repr(u32)]
23    pub enum ItemArmorKind {
24        Shoulder = 0,
25        Chest = 1,
26        Belt = 2,
27        Hand = 3,
28        Pants = 4,
29        Foot = 5,
30        Back = 6,
31        Ring = 7,
32        Neck = 8,
33        Head = 9,
34        Tabard = 10,
35        Bag = 11,
36    }
37);
38
39make_case_elim!(
40    body,
41    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
42    #[repr(u32)]
43    pub enum Body {
44        Tool(tool: ToolKind) = 0,
45        ModularComponent = 1,
46        Lantern = 2,
47        Glider = 3,
48        Armor(armor: ItemArmorKind) = 4,
49        Utility = 5,
50        Consumable = 6,
51        Throwable = 7,
52        Ingredient = 8,
53        Coins = 9,
54        CoinPouch = 10,
55        Empty = 11,
56        Thrown(tool: ToolKind) = 12,
57    }
58);
59
60impl From<Body> for super::Body {
61    fn from(body: Body) -> Self { super::Body::Item(body) }
62}
63
64impl From<&Item> for Body {
65    fn from(item: &Item) -> Self {
66        match &*item.kind() {
67            ItemKind::Tool(Tool { kind, .. }) => Body::Tool(*kind),
68            ItemKind::ModularComponent(_) => Body::ModularComponent,
69            ItemKind::Lantern(_) => Body::Lantern,
70            ItemKind::Glider => Body::Glider,
71            ItemKind::Armor(armor) => match armor.kind {
72                ArmorKind::Shoulder => Body::Armor(ItemArmorKind::Shoulder),
73                ArmorKind::Chest => Body::Armor(ItemArmorKind::Chest),
74                ArmorKind::Belt => Body::Armor(ItemArmorKind::Belt),
75                ArmorKind::Hand => Body::Armor(ItemArmorKind::Hand),
76                ArmorKind::Pants => Body::Armor(ItemArmorKind::Pants),
77                ArmorKind::Foot => Body::Armor(ItemArmorKind::Foot),
78                ArmorKind::Back => Body::Armor(ItemArmorKind::Back),
79                ArmorKind::Backpack => Body::Armor(ItemArmorKind::Back),
80                ArmorKind::Ring => Body::Armor(ItemArmorKind::Ring),
81                ArmorKind::Neck => Body::Armor(ItemArmorKind::Neck),
82                ArmorKind::Head => Body::Armor(ItemArmorKind::Head),
83                ArmorKind::Tabard => Body::Armor(ItemArmorKind::Tabard),
84                ArmorKind::Bag => Body::Armor(ItemArmorKind::Bag),
85            },
86            ItemKind::Utility { kind, .. } => match kind {
87                Utility::Coins => {
88                    if item.amount() > 100 {
89                        Body::CoinPouch
90                    } else {
91                        Body::Coins
92                    }
93                },
94                _ => Body::Utility,
95            },
96            ItemKind::Consumable { .. } => Body::Consumable,
97            ItemKind::Ingredient { .. } => Body::Ingredient,
98            _ => Body::Empty,
99        }
100    }
101}
102
103impl From<&ThrownItem> for Body {
104    fn from(thrown_item: &ThrownItem) -> Self {
105        match &*thrown_item.0.kind() {
106            ItemKind::Tool(Tool { kind, .. }) => Body::Thrown(*kind),
107            _ => Body::Empty,
108        }
109    }
110}
111
112impl Body {
113    pub fn to_string(self) -> &'static str {
114        match self {
115            Body::Tool(_) => "tool",
116            Body::ModularComponent => "modular_component",
117            Body::Lantern => "lantern",
118            Body::Glider => "glider",
119            Body::Armor(_) => "armor",
120            Body::Utility => "utility",
121            Body::Consumable => "consumable",
122            Body::Throwable => "throwable",
123            Body::Ingredient => "ingredient",
124            Body::Coins => "coins",
125            Body::CoinPouch => "coin_pouch",
126            Body::Empty => "empty",
127            Body::Thrown(_) => "thrown",
128        }
129    }
130
131    pub fn density(&self) -> Density { Density(1.1 * WATER_DENSITY) }
132
133    pub fn mass(&self) -> Mass { Mass(2.0) }
134
135    pub fn dimensions(&self) -> Vec3<f32> { Vec3::new(0.0, 0.1, 0.0) }
136
137    pub fn orientation(&self, rng: &mut impl Rng) -> Ori {
138        let random = rng.gen_range(-1.0..1.0f32);
139        let default = Ori::default();
140        match self {
141            Body::Tool(_) | Body::Thrown(_) => default
142                .pitched_down(PI / 2.0)
143                .yawed_left(PI / 2.0)
144                .pitched_towards(
145                    Dir::from_unnormalized(Vec3::new(
146                        random,
147                        rng.gen_range(-1.0..1.0f32),
148                        rng.gen_range(-1.0..1.0f32),
149                    ))
150                    .unwrap_or_default(),
151                ),
152
153            Body::Armor(ItemArmorKind::Neck | ItemArmorKind::Back | ItemArmorKind::Tabard) => {
154                default.yawed_left(random).pitched_down(PI / 2.0)
155            },
156            _ => default.yawed_left(random),
157        }
158    }
159}