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}