Skip to main content

wowlab_engine_application/enemies/
result.rs

1//! Resolved enemy-stat results: the strict combat-construction shape and the inspection partial.
2
3use super::{
4    error::{EnemyStatError, EnemyStatResolutionError},
5    provenance::EnemyStatProvenanceStep,
6};
7
8/// Resolved identity for one enemy.
9#[derive(Clone, Debug, PartialEq)]
10pub struct ResolvedEnemyIdentity {
11    pub display_name: String,
12    pub npc_id: Option<u32>,
13    pub classification: Option<i32>,
14    pub creature_type: Option<i32>,
15}
16
17/// Recorded creature-to-tuning join metadata (J9). It never drives stat inference (A1/A2/A3).
18#[derive(Clone, Debug, PartialEq)]
19pub struct ResolvedCreatureTuning {
20    pub creature_difficulty_row_id: i32,
21    pub content_tuning_id: i32,
22    /// Difficulty IDs in row-ID order.
23    pub difficulty_ids: Vec<i32>,
24}
25
26/// Typed partial resolution for inspection: each component is a value or its exact data error.
27#[derive(Clone, Debug, PartialEq)]
28pub struct EnemyStatInspection {
29    pub(super) identity: Result<ResolvedEnemyIdentity, EnemyStatError>,
30    /// Present only when the creature has exactly one `CreatureDifficulty` variant.
31    pub(super) creature_tuning: Option<ResolvedCreatureTuning>,
32    /// Authored level (A4: no table maps an NPC ID to a level).
33    pub(super) level: u16,
34    pub(super) max_health: Result<f64, EnemyStatError>,
35    pub(super) armor: Result<f64, EnemyStatError>,
36    pub(super) armor_constant: Result<f64, EnemyStatError>,
37    pub(super) auto_attack_dps: Result<f64, EnemyStatError>,
38    pub(super) spell_damage: Result<f64, EnemyStatError>,
39    pub(super) provenance: Vec<EnemyStatProvenanceStep>,
40}
41
42impl EnemyStatInspection {
43    pub fn identity(&self) -> Result<&ResolvedEnemyIdentity, &EnemyStatError> {
44        self.identity.as_ref()
45    }
46
47    #[must_use]
48    pub const fn creature_tuning(&self) -> Option<&ResolvedCreatureTuning> {
49        self.creature_tuning.as_ref()
50    }
51
52    #[must_use]
53    pub const fn level(&self) -> u16 {
54        self.level
55    }
56
57    pub fn max_health(&self) -> Result<f64, &EnemyStatError> {
58        self.max_health.as_ref().copied()
59    }
60
61    pub fn armor(&self) -> Result<f64, &EnemyStatError> {
62        self.armor.as_ref().copied()
63    }
64
65    pub fn armor_constant(&self) -> Result<f64, &EnemyStatError> {
66        self.armor_constant.as_ref().copied()
67    }
68
69    pub fn auto_attack_dps(&self) -> Result<f64, &EnemyStatError> {
70        self.auto_attack_dps.as_ref().copied()
71    }
72
73    pub fn spell_damage(&self) -> Result<f64, &EnemyStatError> {
74        self.spell_damage.as_ref().copied()
75    }
76
77    #[must_use]
78    pub fn provenance(&self) -> &[EnemyStatProvenanceStep] {
79        &self.provenance
80    }
81
82    /// Requires identity, max health, and armor; optional budget/armor-constant metadata never blocks.
83    pub fn into_resolved(self) -> Result<ResolvedEnemyStats, EnemyStatResolutionError> {
84        Ok(ResolvedEnemyStats {
85            identity: self.identity?,
86            creature_tuning: self.creature_tuning,
87            level: self.level,
88            max_health: self.max_health?,
89            armor: self.armor?,
90            armor_constant: self.armor_constant.ok(),
91            auto_attack_dps: self.auto_attack_dps.ok(),
92            spell_damage: self.spell_damage.ok(),
93            provenance: self.provenance,
94        })
95    }
96}
97
98/// Fully resolved enemy stats accepted for combat construction.
99#[derive(Clone, Debug, PartialEq)]
100pub struct ResolvedEnemyStats {
101    identity: ResolvedEnemyIdentity,
102    creature_tuning: Option<ResolvedCreatureTuning>,
103    level: u16,
104    max_health: f64,
105    armor: f64,
106    armor_constant: Option<f64>,
107    auto_attack_dps: Option<f64>,
108    spell_damage: Option<f64>,
109    provenance: Vec<EnemyStatProvenanceStep>,
110}
111
112impl ResolvedEnemyStats {
113    #[must_use]
114    pub const fn identity(&self) -> &ResolvedEnemyIdentity {
115        &self.identity
116    }
117
118    #[must_use]
119    pub const fn creature_tuning(&self) -> Option<&ResolvedCreatureTuning> {
120        self.creature_tuning.as_ref()
121    }
122
123    #[must_use]
124    pub const fn level(&self) -> u16 {
125        self.level
126    }
127
128    #[must_use]
129    pub const fn max_health(&self) -> f64 {
130        self.max_health
131    }
132
133    #[must_use]
134    pub const fn armor(&self) -> f64 {
135        self.armor
136    }
137
138    #[must_use]
139    pub const fn armor_constant(&self) -> Option<f64> {
140        self.armor_constant
141    }
142
143    #[must_use]
144    pub const fn auto_attack_dps(&self) -> Option<f64> {
145        self.auto_attack_dps
146    }
147
148    #[must_use]
149    pub const fn spell_damage(&self) -> Option<f64> {
150        self.spell_damage
151    }
152
153    #[must_use]
154    pub fn provenance(&self) -> &[EnemyStatProvenanceStep] {
155        &self.provenance
156    }
157}