Skip to main content

esf_dogma_engine/calculate/
mod.rs

1mod 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/// What [`calculate()`] reports on top of the values.
26#[cfg_attr(feature = "typescript", derive(Tsify))]
27#[derive(Deserialize, Debug, Default, Clone)]
28#[serde(default)]
29pub struct Options {
30    /// Report per attribute the modifiers its value was calculated from.
31    pub sources: bool,
32    /// Report the fitting rules the fit breaks.
33    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/// One effect aimed at the fit, and the source it reads its strength off.
90#[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
100/// Calculate every attribute of the ship, its items and the character.
101pub 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    /* A burst reaches the whole fleet, and the ship running it is part of that
115     * fleet. How strong it is only shows once calculated, so the fit is done
116     * over with its own buffs handed back to it. */
117    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}