genshin_calc_core/lib.rs
1//! # genshin-calc-core
2//!
3//! Damage and elemental reaction calculation engine for Genshin Impact.
4//!
5//! ## Calculation Pipelines
6//!
7//! | Pipeline | Function | Reactions |
8//! |----------|----------|-----------|
9//! | Standard | [`calculate_damage`] | Amplifying (vaporize/melt), Catalyze (spread/aggravate), or none |
10//! | Transformative | [`calculate_transformative`] | Overloaded, superconduct, electro-charged, swirl, bloom, etc. |
11//! | Lunar | [`calculate_lunar`] | Lunar electro-charged, lunar bloom, lunar crystallize |
12//!
13//! Standard damage passes through ATK/HP/DEF scaling, crit, defense, and resistance.
14//! Transformative damage scales with character level and elemental mastery only (no crit, no defense).
15//! Lunar damage scales like transformative but can crit.
16//!
17//! ## Team Composition
18//!
19//! Build teams with [`TeamMember`] and resolve buffs with [`resolve_team_stats`]:
20//!
21//! ```
22//! use genshin_calc_core::*;
23//!
24//! let dps = TeamMember {
25//! element: Element::Pyro,
26//! weapon_type: WeaponType::Claymore,
27//! stats: StatProfile {
28//! base_atk: 900.0,
29//! crit_rate: 0.60,
30//! crit_dmg: 1.50,
31//! energy_recharge: 1.0,
32//! ..Default::default()
33//! },
34//! buffs_provided: vec![],
35//! is_moonsign: false,
36//! can_nightsoul: false,
37//! };
38//! let support = TeamMember {
39//! element: Element::Pyro,
40//! weapon_type: WeaponType::Sword,
41//! stats: StatProfile {
42//! base_atk: 800.0,
43//! energy_recharge: 1.0,
44//! ..Default::default()
45//! },
46//! buffs_provided: vec![ResolvedBuff {
47//! source: "Bennett Burst".into(),
48//! stat: BuffableStat::AtkFlat,
49//! value: 1000.0,
50//! target: BuffTarget::Team,
51//! origin: None,
52//! }],
53//! is_moonsign: false,
54//! can_nightsoul: false,
55//! };
56//! let result = resolve_team_stats(&[dps, support], 0, &[]).unwrap();
57//! assert!(result.final_stats.atk > 900.0); // DPS gets Bennett's ATK buff
58//! ```
59//!
60//! ## Example
61//!
62//! ```
63//! use genshin_calc_core::*;
64//!
65//! let input = DamageInput {
66//! character_level: 90,
67//! stats: Stats {
68//! atk: 2000.0,
69//! crit_rate: 0.75,
70//! crit_dmg: 1.50,
71//! dmg_bonus: 0.466,
72//! ..Default::default()
73//! },
74//! talent_multiplier: 1.76,
75//! scaling_stat: ScalingStat::Atk,
76//! damage_type: DamageType::Skill,
77//! element: Some(Element::Pyro),
78//! reaction: None,
79//! reaction_bonus: 0.0,
80//! flat_dmg: 0.0,
81//! };
82//! let enemy = Enemy {
83//! level: 90,
84//! resistance: 0.10,
85//! def_reduction: 0.0,
86//! def_ignore: 0.0,
87//! };
88//! let result = calculate_damage(&input, &enemy).unwrap();
89//! assert!(result.average > 0.0);
90//! ```
91
92#![deny(missing_docs)]
93
94/// Buffable stat types for team buffs.
95pub mod buff_types;
96/// Standard damage calculation pipeline.
97pub mod damage;
98/// Elemental mastery bonus formulas.
99pub mod em;
100/// Enemy parameters and debuff application.
101pub mod enemy;
102/// Error types for calculation failures.
103pub mod error;
104/// Character level to reaction base value table.
105pub mod level_table;
106/// Lunar reaction damage calculation pipeline.
107pub mod lunar;
108/// Moonsign character system types and calculations.
109pub mod moonsign;
110/// Elemental reaction types and properties.
111pub mod reaction;
112/// Elemental resonance system.
113pub mod resonance;
114/// Stat profile (base/percent/flat breakdown) and combination.
115pub mod stat_profile;
116/// Final combined character stats.
117pub mod stats;
118/// Team composition and buff resolution.
119pub mod team;
120/// Transformative reaction damage calculation pipeline.
121pub mod transformative;
122/// Core type enums: Element, DamageType, ScalingStat, WeaponType.
123pub mod types;
124
125pub use buff_types::BuffableStat;
126pub use damage::{DamageInput, DamageResult, calculate_damage, collect_flat_dmg};
127pub use em::{amplifying_em_bonus, catalyze_em_bonus, lunar_em_bonus, transformative_em_bonus};
128pub use enemy::{
129 Enemy, EnemyDebuffs, apply_debuffs_to_enemy, apply_enemy_debuffs, superconduct_debuff,
130};
131pub use error::CalcError;
132pub use level_table::reaction_base_value;
133pub use lunar::{LunarInput, LunarResult, calculate_lunar};
134pub use moonsign::{
135 LunarContribution, MoonsignBenediction, MoonsignContext, MoonsignLevel, MoonsignTalentEffect,
136 MoonsignTalentEnhancement, NonMoonsignLunarBuff, apply_moonsign_enhancements,
137 calculate_lunar_team, calculate_non_moonsign_bonus, determine_moonsign_level,
138 non_moonsign_scaling, resolve_moonsign_context, select_non_moonsign_buff,
139};
140pub use reaction::{Reaction, ReactionCategory, determine_reaction};
141pub use resonance::{
142 ElementalResonance, determine_resonances, resonance_buffs, resonance_conditional_buffs,
143};
144pub use stat_profile::{StatProfile, combine_stats};
145pub use stats::Stats;
146pub use team::{
147 BuffTarget, DamageContext, ResolvedBuff, TeamMember, TeamResolveResult, apply_buffs_to_profile,
148 resolve_team_stats, resolve_team_stats_detailed,
149};
150pub use transformative::{TransformativeInput, TransformativeResult, calculate_transformative};
151pub use types::{DamageType, Element, ScalingStat, WeaponType};
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_public_api_usage_example() {
159 let stats = Stats {
160 hp: 20000.0,
161 atk: 2000.0,
162 def: 800.0,
163 elemental_mastery: 100.0,
164 crit_rate: 0.75,
165 crit_dmg: 1.50,
166 energy_recharge: 1.20,
167 dmg_bonus: 0.466,
168 ..Default::default()
169 };
170
171 let input = DamageInput {
172 character_level: 90,
173 stats,
174 talent_multiplier: 1.76,
175 scaling_stat: ScalingStat::Atk,
176 damage_type: DamageType::Skill,
177 element: Some(Element::Pyro),
178 reaction: None,
179 reaction_bonus: 0.0,
180 flat_dmg: 0.0,
181 };
182
183 let enemy = Enemy {
184 level: 90,
185 resistance: 0.10,
186 def_reduction: 0.0,
187 def_ignore: 0.0,
188 };
189
190 let result = calculate_damage(&input, &enemy).unwrap();
191 assert!(result.non_crit > 0.0);
192 assert!(result.crit > result.non_crit);
193 assert!(result.average > result.non_crit);
194 assert!(result.average < result.crit);
195 }
196}