1use wowlab_engine_gamedata::{ItemBudget, RatingMultiplierSlot, ResolvedGameTables};
4use wowlab_types::data::{ItemDataFlat, ItemQuality, RandPropPointsUse};
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, num_enum::TryFromPrimitive)]
8#[repr(i32)]
9#[non_exhaustive]
10pub enum InventoryType {
11 NonEquippable = 0,
12 Head = 1,
13 Neck = 2,
14 Shoulder = 3,
15 Body = 4,
16 Chest = 5,
17 Waist = 6,
18 Legs = 7,
19 Feet = 8,
20 Wrists = 9,
21 Hands = 10,
22 Finger = 11,
23 Trinket = 12,
24 Weapon = 13,
25 Shield = 14,
26 Ranged = 15,
27 Cloak = 16,
28 TwoHandWeapon = 17,
29 Bag = 18,
30 Tabard = 19,
31 Robe = 20,
32 MainHandWeapon = 21,
33 OffHandWeapon = 22,
34 Holdable = 23,
35 Ammo = 24,
36 Thrown = 25,
37 RangedRight = 26,
38 Relic = 28,
39}
40
41const INVENTORY_TYPES: &[(i32, InventoryType, &str)] = &[
42 (0, InventoryType::NonEquippable, "Non-equippable"),
43 (1, InventoryType::Head, "Head"),
44 (2, InventoryType::Neck, "Neck"),
45 (3, InventoryType::Shoulder, "Shoulder"),
46 (4, InventoryType::Body, "Shirt"),
47 (5, InventoryType::Chest, "Chest"),
48 (6, InventoryType::Waist, "Waist"),
49 (7, InventoryType::Legs, "Legs"),
50 (8, InventoryType::Feet, "Feet"),
51 (9, InventoryType::Wrists, "Wrist"),
52 (10, InventoryType::Hands, "Hands"),
53 (11, InventoryType::Finger, "Finger"),
54 (12, InventoryType::Trinket, "Trinket"),
55 (13, InventoryType::Weapon, "One-Hand"),
56 (14, InventoryType::Shield, "Shield"),
57 (15, InventoryType::Ranged, "Ranged"),
58 (16, InventoryType::Cloak, "Back"),
59 (17, InventoryType::TwoHandWeapon, "Two-Hand"),
60 (18, InventoryType::Bag, "Bag"),
61 (19, InventoryType::Tabard, "Tabard"),
62 (20, InventoryType::Robe, "Robe"),
63 (21, InventoryType::MainHandWeapon, "Main Hand"),
64 (22, InventoryType::OffHandWeapon, "Off Hand"),
65 (23, InventoryType::Holdable, "Held In Off-Hand"),
66 (24, InventoryType::Ammo, "Ammo"),
67 (25, InventoryType::Thrown, "Thrown"),
68 (26, InventoryType::RangedRight, "Ranged Right"),
69 (28, InventoryType::Relic, "Relic"),
70];
71
72impl InventoryType {
73 #[must_use]
74 pub fn display_name(self) -> &'static str {
75 INVENTORY_TYPES
76 .iter()
77 .find_map(|&(_, kind, name)| (kind == self).then_some(name))
78 .unwrap_or("Unknown")
79 }
80}
81
82#[derive(Clone, Copy, Debug, Eq, PartialEq, num_enum::TryFromPrimitive)]
84#[repr(i32)]
85#[non_exhaustive]
86pub enum ItemClass {
87 Consumable = 0,
88 Container = 1,
89 Weapon = 2,
90 Gem = 3,
91 Armor = 4,
92 Reagent = 5,
93 Projectile = 6,
94 TradeGoods = 7,
95 ItemEnhancement = 8,
96 Recipe = 9,
97 Money = 10,
98 Quiver = 11,
99 Quest = 12,
100 Key = 13,
101 Permanent = 14,
102 Miscellaneous = 15,
103 Glyph = 16,
104 BattlePet = 17,
105 Token = 18,
106 WowToken = 19,
107 Profession = 20,
108}
109
110#[must_use]
112pub fn item_matches_consumable_query(item: &ItemDataFlat, name_token: &str, subclass: i32) -> bool {
113 ItemClass::try_from(item.class_id).ok() == Some(ItemClass::Consumable)
114 && item.subclass_id == subclass
115 && wowlab_engine_ports::tokenize_name(&item.name).contains(name_token)
116}
117
118#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, num_enum::TryFromPrimitive)]
120#[repr(i32)]
121#[non_exhaustive]
122pub enum ItemEffectTrigger {
123 #[default]
124 OnUse = 0,
125 OnEquip = 1,
126 ChanceOnHit = 2,
127 Soulstone = 4,
128 OnUseNoDelay = 5,
129 LearnSpell = 6,
130}
131
132#[derive(Clone, Copy, Debug, Eq, PartialEq)]
134#[repr(i32)]
135#[non_exhaustive]
136pub enum ConsumableSubclass {
137 Potion = 1,
138 Flask = 3,
139 Food = 5,
140}
141
142#[derive(Clone, Copy, Debug, Eq, PartialEq)]
144#[repr(i32)]
145#[non_exhaustive]
146pub enum GemSubclass {
147 ArtifactRelic = 11,
148}
149
150#[derive(Clone, Copy, Debug, Eq, PartialEq)]
152#[repr(i32)]
153#[non_exhaustive]
154pub enum ArmorSubclass {
155 Cloth = 1,
156 Leather = 2,
157 Mail = 3,
158 Plate = 4,
159}
160
161#[derive(Clone, Copy, Debug, Eq, PartialEq, num_enum::TryFromPrimitive)]
163#[repr(i32)]
164#[non_exhaustive]
165pub enum WeaponSubclass {
166 Bow = 2,
167 Gun = 3,
168 Thrown = 16,
169 Crossbow = 18,
170 Wand = 19,
171}
172
173#[must_use]
175pub fn resolve_item_budget(
176 tables: &ResolvedGameTables,
177 item_level: i32,
178 raw_quality: i32,
179 slot: RatingMultiplierSlot,
180) -> Option<ItemBudget> {
181 let quality = ItemQuality::from_dbc(raw_quality)?;
182 let row = tables.rand_prop_points_row(item_level)?;
183 let bucket = quality.rand_prop_points_bucket(RandPropPointsUse::ItemEffect)?;
184 let stat = row.budget(bucket, 0);
185 let rating = stat * crate::stats::rating_multiplier_at_ilvl(tables, slot, item_level);
186
187 Some(ItemBudget {
188 item_level,
189 stat,
190 rating,
191 })
192}
193
194#[cfg(test)]
195mod tests;