esf_dogma_engine/calculate/
mod.rs1mod attribute_ids;
2mod item;
3mod outgoing;
4mod output;
5mod pass_1;
6mod pass_2;
7mod pass_3;
8mod pass_4;
9
10use serde::Deserialize;
11
12#[cfg(feature = "typescript")]
13use tsify::Tsify;
14
15use crate::fit::Fit;
16use crate::projection::ProjectedBuff;
17use crate::validate::validate;
18use esf_data::Info;
19use item::{Item, Object};
20
21pub use item::EffectOperator;
22pub use outgoing::beacon;
23pub use output::{AttributeValue, Calculation, ItemResult, Source, SourceRef};
24
25#[cfg_attr(feature = "typescript", derive(Tsify))]
27#[derive(Deserialize, Debug, Default, Clone)]
28#[serde(default)]
29pub struct Options {
30 pub sources: bool,
32 pub validate: bool,
34}
35
36#[derive(Debug)]
37pub(crate) struct Objects {
38 pub ship: Item,
39 pub mode: Option<Item>,
40 pub items: Vec<Item>,
41 pub skills: Vec<Item>,
42 pub char: Item,
43 pub projected: Vec<Projected>,
44 pub buffs: Vec<ProjectedBuff>,
45 pub sources: bool,
46 pub reactive_armor: Option<[f64; 4]>,
47}
48
49impl Objects {
50 fn get(&self, object: Object) -> Option<&Item> {
51 match object {
52 Object::Ship => Some(&self.ship),
53 Object::Mode => self.mode.as_ref(),
54 Object::Char => Some(&self.char),
55 Object::Projected(index) => Some(&self.projected[index].item),
56 Object::Item(index) => Some(&self.items[index]),
57 Object::Charge(index) => self.items[index].charge.as_deref(),
58 Object::Skill(index) => Some(&self.skills[index]),
59 }
60 }
61
62 fn get_mut(&mut self, object: Object) -> Option<&mut Item> {
63 match object {
64 Object::Ship => Some(&mut self.ship),
65 Object::Mode => self.mode.as_mut(),
66 Object::Char => Some(&mut self.char),
67 Object::Projected(index) => Some(&mut self.projected[index].item),
68 Object::Item(index) => Some(&mut self.items[index]),
69 Object::Charge(index) => self.items[index].charge.as_deref_mut(),
70 Object::Skill(index) => Some(&mut self.skills[index]),
71 }
72 }
73
74 pub fn new(ship_type_id: i32, mode_type_id: Option<i32>) -> Objects {
75 Objects {
76 ship: Item::new_fake(ship_type_id),
77 mode: mode_type_id.map(Item::new_fake),
78 items: Vec::new(),
79 skills: Vec::new(),
80 char: Item::new_fake(1373),
81 projected: Vec::new(),
82 buffs: Vec::new(),
83 sources: false,
84 reactive_armor: None,
85 }
86 }
87}
88
89#[derive(Debug)]
91pub(crate) struct Projected {
92 pub effect_id: i32,
93 pub item: Item,
94}
95
96trait Pass {
97 fn pass(info: &impl Info, objects: &mut Objects);
98}
99
100pub fn calculate(info: &impl Info, fit: &Fit, options: &Options) -> Calculation {
102 let mut calculation = calculate_with_bursts(info, fit, options);
103
104 if options.validate {
105 calculation.violations = Some(validate(info, fit, &calculation));
106 }
107
108 calculation
109}
110
111fn calculate_with_bursts(info: &impl Info, fit: &Fit, options: &Options) -> Calculation {
112 let calculation = calculate_once(info, fit, options);
113
114 if calculation.outgoing.buffs.is_empty() {
118 return calculation;
119 }
120
121 let mut fit = fit.clone();
122 fit.incoming.buffs.extend(calculation.outgoing.buffs);
123
124 calculate_once(info, &fit, options)
125}
126
127fn calculate_once(info: &impl Info, fit: &Fit, options: &Options) -> Calculation {
128 let mut objects = pass_1::PassOne::pass(info, fit);
129 objects.sources = options.sources;
130
131 pass_2::PassTwo::pass(info, &mut objects);
132 pass_3::PassThree::pass(info, &mut objects);
133 pass_4::PassFour::pass(info, &mut objects);
134
135 Calculation::new(info, &objects)
136}