Skip to main content

yog_registry/
items.rs

1//! Items: what a mod declares an item as (food, hangings, its look).
2
3use crate::{ArmorPiece, ArmorSlot, ToolItem};
4
5/// Nutritional properties for a food item.
6#[derive(yog_data::Schema, Debug, Clone)]
7pub struct FoodDef {
8    /// Hunger points restored (1 unit = half a drumstick).
9    pub nutrition: u32,
10    /// Saturation modifier applied after eating.
11    pub saturation: f32,
12    /// If `true`, edible even when the hunger bar is full.
13    pub can_always_eat: bool,
14}
15
16impl FoodDef {
17    pub fn new(nutrition: u32, saturation: f32) -> Self {
18        Self {
19            nutrition,
20            saturation,
21            can_always_eat: false,
22        }
23    }
24
25    pub fn can_always_eat(mut self) -> Self {
26        self.can_always_eat = true;
27        self
28    }
29}
30
31/// A custom item to register, identified by `namespace:path`.
32#[derive(yog_data::Schema, Debug, Clone)]
33pub struct ItemDef {
34    pub id: String,
35    pub max_stack: u8,
36    pub name: Option<String>,
37    pub tooltip: Option<String>,
38    /// Durability. `0` = non-damageable. If set, `max_stack` is forced to 1.
39    pub max_damage: u32,
40    /// Immune to fire and lava damage (like netherite items).
41    pub fire_resistant: bool,
42    /// Furnace fuel burn time in ticks (`0` = not fuel; 200 = one coal equivalent).
43    pub fuel_ticks: u32,
44    /// Nutritional properties; `None` = not food.
45    pub food: Option<FoodDef>,
46    /// A tool or a weapon of a material.
47    pub tool: Option<ToolItem>,
48    /// A piece of armor of a material.
49    pub armor: Option<ArmorPiece>,
50    /// Worn in this slot without being armor.
51    pub wearable: Option<ArmorSlot>,
52    /// Used on a block's side, it hangs there as an entity of a hanging type.
53    pub hangs: Option<Hangs>,
54}
55
56/// What an item hangs on a wall ([`ItemDef::hangs`]).
57#[derive(yog_data::Schema, Debug, Clone, PartialEq)]
58pub struct Hangs {
59    /// A hanging entity type ([`EntityKind::Hanging`]).
60    pub entity: String,
61    /// Whole blocks of wall, wide and high; `None`: the type's size.
62    pub size: Option<[u32; 2]>,
63}
64
65impl ItemDef {
66    pub fn new(id: impl Into<String>) -> Self {
67        Self {
68            id: id.into(),
69            max_stack: 64,
70            name: None,
71            tooltip: None,
72            max_damage: 0,
73            fire_resistant: false,
74            fuel_ticks: 0,
75            food: None,
76            tool: None,
77            armor: None,
78            wearable: None,
79            hangs: None,
80        }
81    }
82
83    /// A tool (`pickaxe`, `axe`, `shovel`, `hoe`, a mod's mineable tag
84    /// `mymod:mineable/hammer`) or a `sword`, of `material` (a
85    /// [`ToolMaterial`]: the game's `iron`… or a mod's), attacking as the
86    /// game's tool of the kind does ([`Self::tool_attack`] changes it).
87    pub fn tool(mut self, kind: impl Into<String>, material: impl Into<String>) -> Self {
88        self.tool = Some(ToolItem {
89            kind: kind.into(),
90            material: material.into(),
91            attack_damage: None,
92            attack_speed: None,
93        });
94        self
95    }
96
97    /// The tool's own attack damage (on top of the material's) and speed
98    /// change; none: the game's tool's. Nothing without [`Self::tool`].
99    pub fn tool_attack(mut self, damage: Option<f32>, speed: Option<f32>) -> Self {
100        if let Some(t) = &mut self.tool {
101            t.attack_damage = damage;
102            t.attack_speed = speed;
103        }
104        self
105    }
106
107    /// A piece of armor for `slot` (`head`, `chest`, `legs`, `feet`) of
108    /// `material` (an [`ArmorMaterial`]: the game's `diamond`… or a mod's).
109    pub fn armor(mut self, slot: ArmorSlot, material: impl Into<String>) -> Self {
110        self.armor = Some(ArmorPiece {
111            slot,
112            material: material.into(),
113        });
114        self
115    }
116
117    /// Worn in `slot` without being armor.
118    pub fn wearable(mut self, slot: ArmorSlot) -> Self {
119        self.wearable = Some(slot);
120        self
121    }
122
123    /// Used on a block's side, it hangs an `entity` (a hanging type) there,
124    /// `size` blocks wide and high (`None`: the type's own); the entity
125    /// keeps one of this item and drops it when it breaks.
126    pub fn hangs(mut self, entity: impl Into<String>, size: Option<[u32; 2]>) -> Self {
127        self.hangs = Some(Hangs {
128            entity: entity.into(),
129            size,
130        });
131        self
132    }
133
134    /// Maximum stack size (default 64). Ignored when `max_damage` is set.
135    pub fn max_stack(mut self, n: u8) -> Self {
136        self.max_stack = n;
137        self
138    }
139
140    /// Display name shown in-game.
141    pub fn name(mut self, name: impl Into<String>) -> Self {
142        self.name = Some(name.into());
143        self
144    }
145
146    /// A tooltip line shown on hover.
147    pub fn tooltip(mut self, tooltip: impl Into<String>) -> Self {
148        self.tooltip = Some(tooltip.into());
149        self
150    }
151
152    /// Make this a damageable item (tool/weapon/armour). Forces stack size to 1.
153    pub fn max_damage(mut self, durability: u32) -> Self {
154        self.max_damage = durability;
155        self
156    }
157
158    /// Make this item fire-resistant (won't burn in fire or lava).
159    pub fn fire_resistant(mut self) -> Self {
160        self.fire_resistant = true;
161        self
162    }
163
164    /// Register as furnace fuel burning for `ticks` (200 ticks = 1 item smelted).
165    pub fn fuel(mut self, ticks: u32) -> Self {
166        self.fuel_ticks = ticks;
167        self
168    }
169
170    /// Make this item edible with the given nutritional properties.
171    pub fn food(mut self, food: FoodDef) -> Self {
172        self.food = Some(food);
173        self
174    }
175}