wowlab_engine_content/
items.rs1use wowlab_engine_combat::CombatSystemBuilder;
2use wowlab_engine_domain::dbc::resolve_item_budget;
3use wowlab_engine_gamedata::{ItemBudget, ResolvedGameData, rating_multiplier_slot_for_gear};
4use wowlab_engine_ports::{EngineError, EquippedItem};
5
6macro_rules! register_item {
7 (
8 $builder:expr, $data:expr, $display:expr
9 $(, rppm: ($item_id:expr, $ppm:expr, $haste:expr))?
10 $(, rppm_driver: ($driver_item_id:expr, $driver_spell_id:expr))?
11 $(, auras: ($budget:expr) [ $( ($aura_const:expr, $aura_fn:ident) ),* $(,)? ])?
12 $(, spells: [ $( ($spell_const:expr, $spell_fn:ident) ),* $(,)? ])?
13 $(, precombat: [ $( $precombat_const:expr ),* $(,)? ])?
14 $(,)?
15 ) => {{
16 let data = $data;
17 let display = $display;
18 let builder = $builder;
19 $( let builder = builder.register_item_rppm($item_id, $ppm, $haste); )?
20 $( let builder = builder.register_item_rppm_from_data($driver_item_id, $driver_spell_id); )?
21 $(
22 let budget = $budget;
23 $( let builder = builder.aura(display, $aura_const, |a| $aura_fn(a, data, budget)); )*
24 )?
25 $($( let builder = builder.spell(display, $spell_const, |s| $spell_fn(s, data)); )*)?
26 $($( let builder = builder.precombat_aura_id($precombat_const); )*)?
27 builder
28 }};
29}
30
31pub(crate) use register_item;
32
33pub(crate) fn item_budget(
34 data: &ResolvedGameData,
35 item: &EquippedItem,
36) -> Result<ItemBudget, EngineError> {
37 let slot = rating_multiplier_slot_for_gear(item.slot);
38
39 if let Some(budget) =
40 resolve_item_budget(data.game_tables(), item.item_level, item.quality, slot)
41 {
42 return Ok(budget);
43 }
44
45 if data.is_empty() {
46 return Ok(ItemBudget::default());
47 }
48
49 Err(EngineError::spec_construction(format!(
50 "missing item budget for equipped item {} at item level {} with quality {}",
51 item.item_id, item.item_level, item.quality
52 )))
53}
54
55pub(crate) fn register_simple_equip_auras(
56 data: &ResolvedGameData,
57 display: &str,
58 aura_ids: &[u32],
59 create_builder: impl FnOnce() -> CombatSystemBuilder,
60) -> CombatSystemBuilder {
61 let mut builder = create_builder();
62
63 for &aura_id in aura_ids {
64 builder = builder.aura(display, aura_id, |aura| {
65 let spell = wowlab_types::sim::SpellIdx::from_raw(aura_id);
66 let duration = data.aura_duration_ms(spell).ok_or_else(|| {
67 wowlab_engine_combat::BuilderError::missing_spell_data(aura_id, "aura_duration_ms")
68 })?;
69 let max_stacks = data.aura_max_stacks(spell).ok_or_else(|| {
70 wowlab_engine_combat::BuilderError::missing_spell_data(aura_id, "aura_max_stacks")
71 })?;
72
73 Ok(aura
74 .on_player()
75 .duration_ms(duration)
76 .max_stacks(max_stacks))
77 });
78 }
79
80 builder
81}
82
83#[cfg(test)]
84#[path = "items/arcanoweave_cord_tests.rs"]
85mod arcanoweave_cord_tests;
86
87#[cfg(test)]
88#[path = "items/item_budget_tests.rs"]
89mod item_budget_tests;
90
91#[cfg(test)]
92#[path = "items/registration_tests.rs"]
93mod registration_tests;
94
95#[cfg(test)]
96#[path = "items/rotbloom_tests.rs"]
97mod rotbloom_tests;