wowlab_engine_combat/builder/combat_builder/
entities.rs1use wowlab_engine_domain::rotation::to_simc_key;
2
3use super::CombatSystemBuilder;
4use crate::builder::{
5 AuraDefinitionDraft, AutoAttackDefinitionDraft, BuilderError, SpellDefinitionDraft,
6};
7
8impl CombatSystemBuilder {
9 pub fn spell(
15 mut self,
16 name: &str,
17 id: u32,
18 f: impl FnOnce(SpellDefinitionDraft) -> Result<SpellDefinitionDraft, BuilderError>,
19 ) -> Self {
20 if self.pending_error.is_some() {
21 return self;
22 }
23
24 let mut builder = match f(SpellDefinitionDraft::new(name, id)) {
25 Ok(b) => b,
26 Err(e) => {
27 self.pending_error = Some(e);
28
29 return self;
30 }
31 };
32
33 let aura_ids = std::mem::take(&mut builder.applies_aura_ids);
34
35 for aura_id in aura_ids {
36 if let Some(pos) = self.aura_defs.iter().position(|a| a.aura_id == aura_id) {
37 builder = builder.applies_aura(crate::LocalAuraIdx::new(
38 u8::try_from(pos).expect("aura count fits in u8"),
39 ));
40 } else {
41 self.pending_error = Some(crate::builder::BuilderErrorKind::GameData(
42 wowlab_engine_ports::EngineError::spec_construction(format!(
44 "applies_aura_id: aura {aura_id} is not registered before spell {name} ({id})"
45 )),
46 )
47 .into());
48
49 return self;
50 }
51 }
52
53 self.spell_ids.insert(name.to_string(), id);
54
55 if builder.cooldown_secs.is_some() {
56 let snake = to_simc_key(name);
57
58 self.hints.cooldown_spells.push(snake.clone());
59
60 if builder.max_charges > 0 {
61 self.hints.charged_spells.push(snake);
62 }
63 }
64
65 let hook = builder.hook;
66 let empower_release_hook = builder.empower_release_hook;
67 let tick_hook = builder.tick_hook;
68
69 self.spells.push(builder.finalize(name.to_string(), id));
70 self.cast_hooks.push(hook);
71 self.empower_release_hooks.push(empower_release_hook);
72 self.tick_hooks.push(tick_hook);
73
74 self
75 }
76
77 pub fn aura(
78 mut self,
79 name: &str,
80 id: u32,
81 f: impl FnOnce(AuraDefinitionDraft) -> Result<AuraDefinitionDraft, BuilderError>,
82 ) -> Self {
83 if self.pending_error.is_some() {
84 return self;
85 }
86
87 let builder = match f(AuraDefinitionDraft::new(name, id)) {
88 Ok(b) => b,
89 Err(e) => {
90 self.pending_error = Some(e);
91
92 return self;
93 }
94 };
95
96 if builder.on_tick.is_some() && builder.periodic.is_none() {
97 self.pending_error = Some(
98 crate::builder::BuilderErrorKind::GameData(
99 wowlab_engine_ports::EngineError::spec_construction(format!(
100 "aura {name} ({id}): tick_hook requires a registered periodic"
101 )),
102 )
103 .into(),
104 );
105
106 return self;
107 }
108
109 self.aura_ids.insert(name.to_string(), id);
110
111 if builder.periodic.is_some() {
112 self.hints.dot_auras.push(to_simc_key(name));
113 }
114
115 self.aura_defs.push(builder.finalize());
116
117 self
118 }
119
120 pub fn auto_attack(
121 mut self,
122 f: impl FnOnce(AutoAttackDefinitionDraft) -> AutoAttackDefinitionDraft,
123 ) -> Self {
124 self.auto_attacks.push(f(AutoAttackDefinitionDraft::new()));
125
126 self
127 }
128}