complex/
complex.rs

1//! Complex example: Multiple sources, transforms, and dependency chains
2//!
3//! This example demonstrates:
4//! - Complex stat calculations
5//! - Multiple sources per stat
6//! - Transform chains
7//! - Multi-level dependencies
8
9use zzstat::source::ConstantSource;
10use zzstat::transform::{ClampTransform, MultiplicativeTransform, ScalingTransform};
11use zzstat::*;
12
13fn main() -> Result<(), StatError> {
14    let mut resolver = StatResolver::new();
15
16    // Define a character's stats
17    let str_id = StatId::from_str("STR");
18    let dex_id = StatId::from_str("DEX");
19    let int_id = StatId::from_str("INT");
20    let hp_id = StatId::from_str("HP");
21    let mp_id = StatId::from_str("MP");
22    let atk_id = StatId::from_str("ATK");
23    let crit_id = StatId::from_str("CRIT");
24    let dps_id = StatId::from_str("DPS");
25
26    println!("=== Character Stat System ===\n");
27
28    // Base attributes
29    println!("Base Attributes:");
30    resolver.register_source(str_id.clone(), Box::new(ConstantSource(20.0)));
31    println!("  STR: 20");
32
33    resolver.register_source(dex_id.clone(), Box::new(ConstantSource(15.0)));
34    println!("  DEX: 15");
35
36    resolver.register_source(int_id.clone(), Box::new(ConstantSource(25.0)));
37    println!("  INT: 25");
38
39    // HP: Base + STR scaling + item bonuses
40    println!("\nHP Calculation:");
41    resolver.register_source(hp_id.clone(), Box::new(ConstantSource(100.0)));
42    println!("  Base: 100");
43
44    resolver.register_source(hp_id.clone(), Box::new(ConstantSource(50.0)));
45    println!("  Item bonus: +50");
46
47    resolver.register_transform(
48        hp_id.clone(),
49        Box::new(ScalingTransform::new(str_id.clone(), 5.0)),
50    );
51    println!("  STR scaling: +STR * 5");
52
53    resolver.register_transform(hp_id.clone(), Box::new(MultiplicativeTransform::new(1.1)));
54    println!("  Passive: +10%");
55
56    // MP: Base + INT scaling
57    println!("\nMP Calculation:");
58    resolver.register_source(mp_id.clone(), Box::new(ConstantSource(50.0)));
59    println!("  Base: 50");
60
61    resolver.register_transform(
62        mp_id.clone(),
63        Box::new(ScalingTransform::new(int_id.clone(), 3.0)),
64    );
65    println!("  INT scaling: +INT * 3");
66
67    // ATK: Base + STR scaling + DEX scaling
68    println!("\nATK Calculation:");
69    resolver.register_source(atk_id.clone(), Box::new(ConstantSource(30.0)));
70    println!("  Base: 30");
71
72    resolver.register_transform(
73        atk_id.clone(),
74        Box::new(ScalingTransform::new(str_id.clone(), 2.0)),
75    );
76    println!("  STR scaling: +STR * 2");
77
78    resolver.register_transform(
79        atk_id.clone(),
80        Box::new(ScalingTransform::new(dex_id.clone(), 1.0)),
81    );
82    println!("  DEX scaling: +DEX * 1");
83
84    resolver.register_transform(atk_id.clone(), Box::new(ClampTransform::new(0.0, 200.0)));
85    println!("  Clamp: [0, 200]");
86
87    // CRIT: Base + DEX scaling
88    println!("\nCRIT Calculation:");
89    resolver.register_source(crit_id.clone(), Box::new(ConstantSource(5.0)));
90    println!("  Base: 5");
91
92    resolver.register_transform(
93        crit_id.clone(),
94        Box::new(ScalingTransform::new(dex_id.clone(), 2.0)),
95    );
96    println!("  DEX scaling: +DEX * 2");
97
98    // DPS: Depends on ATK and CRIT
99    println!("\nDPS Calculation:");
100    resolver.register_source(dps_id.clone(), Box::new(ConstantSource(0.0)));
101    println!("  Base: 0");
102
103    resolver.register_transform(
104        dps_id.clone(),
105        Box::new(ScalingTransform::new(atk_id.clone(), 1.0)),
106    );
107    println!("  ATK contribution: +ATK * 1");
108
109    resolver.register_transform(
110        dps_id.clone(),
111        Box::new(ScalingTransform::new(crit_id.clone(), 0.5)),
112    );
113    println!("  CRIT contribution: +CRIT * 0.5");
114
115    let context = StatContext::new();
116
117    println!("\n=== Resolving All Stats ===\n");
118    let results = resolver.resolve_all(&context)?;
119
120    // Display final stats
121    println!("=== Final Character Stats ===\n");
122
123    let stats = vec![
124        ("STR", &str_id),
125        ("DEX", &dex_id),
126        ("INT", &int_id),
127        ("HP", &hp_id),
128        ("MP", &mp_id),
129        ("ATK", &atk_id),
130        ("CRIT", &crit_id),
131        ("DPS", &dps_id),
132    ];
133
134    for (name, id) in stats {
135        if let Some(resolved) = results.get(id) {
136            println!("{}: {:.2}", name, resolved.value);
137        }
138    }
139
140    println!("\n=== Detailed Breakdown ===\n");
141
142    // Show detailed breakdown for DPS
143    if let Some(dps) = results.get(&dps_id) {
144        println!("DPS Breakdown:");
145        println!("  Final Value: {:.2}", dps.value);
146
147        println!("\n  Sources:");
148        for (desc, value) in &dps.sources {
149            println!("    {}: {:.2}", desc, value);
150        }
151
152        println!("\n  Transforms:");
153        for (desc, value) in &dps.transforms {
154            println!("    {}: {:.2}", desc, value);
155        }
156    }
157
158    Ok(())
159}