esf_dogma_engine/calculate/
output.rs1use std::collections::BTreeMap;
2
3use serde::Serialize;
4
5#[cfg(feature = "typescript")]
6use tsify::Tsify;
7
8use esf_data::Info;
9
10use super::Objects;
11use super::item::{EffectOperator, Item, Object};
12use super::outgoing::outgoing;
13use crate::fit::State;
14use crate::projection::{ProjectedBuff, Projection};
15use crate::validate::Violation;
16
17#[cfg_attr(feature = "typescript", derive(Tsify))]
19#[derive(Serialize, Debug)]
20pub struct Calculation {
21 pub ship: ItemResult,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub mode: Option<ItemResult>,
26 pub items: Vec<ItemResult>,
28 pub character: ItemResult,
30 #[serde(skip_serializing_if = "Vec::is_empty")]
34 #[cfg_attr(feature = "typescript", tsify(optional))]
35 pub buffs: Vec<ProjectedBuff>,
36 #[serde(skip_serializing_if = "Projection::is_empty")]
38 #[cfg_attr(feature = "typescript", tsify(optional))]
39 pub outgoing: Projection,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 #[cfg_attr(feature = "typescript", tsify(optional))]
43 pub violations: Option<Vec<Violation>>,
44}
45
46#[cfg_attr(feature = "typescript", derive(Tsify))]
48#[derive(Serialize, Debug)]
49pub struct ItemResult {
50 pub attributes: BTreeMap<i32, AttributeValue>,
52 pub state: State,
54 pub max_state: State,
56 pub charge: Option<Box<ItemResult>>,
58}
59
60#[cfg_attr(feature = "typescript", derive(Tsify))]
62#[derive(Serialize, Debug)]
63pub struct AttributeValue {
64 pub base: f64,
66 pub value: f64,
68 #[serde(skip_serializing_if = "Vec::is_empty")]
70 #[cfg_attr(feature = "typescript", tsify(optional))]
71 pub sources: Vec<Source>,
72}
73
74#[cfg_attr(feature = "typescript", derive(Tsify))]
76#[derive(Serialize, Debug, Clone)]
77pub struct Source {
78 pub from: SourceRef,
80 pub effect_id: Option<i32>,
82 pub source_attribute_id: Option<i32>,
85 pub operator: EffectOperator,
87 pub value: f64,
89 pub quantity: u32,
91 pub penalty: Option<f64>,
93 pub applied: bool,
95}
96
97#[cfg_attr(feature = "typescript", derive(Tsify))]
101#[derive(Serialize, Debug, Clone, Copy, PartialEq)]
102#[serde(tag = "type", rename_all = "snake_case")]
103pub enum SourceRef {
104 Ship,
106 Mode,
108 Character,
110 Item {
112 index: usize,
114 },
115 Charge {
117 index: usize,
119 },
120 Skill {
122 type_id: i32,
124 },
125 Projected {
127 index: usize,
129 },
130 Buff {
132 id: i32,
134 },
135}
136
137impl SourceRef {
138 pub(super) fn new(object: Object, type_id: i32) -> SourceRef {
139 match object {
140 Object::Ship => SourceRef::Ship,
141 Object::Mode => SourceRef::Mode,
142 Object::Char => SourceRef::Character,
143 Object::Item(index) => SourceRef::Item { index },
144 Object::Charge(index) => SourceRef::Charge { index },
145 Object::Skill(_) => SourceRef::Skill { type_id },
146 Object::Projected(index) => SourceRef::Projected { index },
147 }
148 }
149}
150
151impl ItemResult {
152 fn new(item: &Item) -> ItemResult {
153 ItemResult {
154 attributes: item
155 .attributes
156 .iter()
157 .map(|(attribute_id, attribute)| {
158 let value = AttributeValue {
159 base: attribute.base_value,
160 value: attribute.value.get().unwrap_or(attribute.base_value),
161 sources: attribute.sources.borrow().clone(),
162 };
163 (*attribute_id, value)
164 })
165 .collect(),
166 state: item.state.into(),
167 max_state: item.max_state.into(),
168 charge: item
169 .charge
170 .as_deref()
171 .map(|charge| Box::new(ItemResult::new(charge))),
172 }
173 }
174}
175
176impl Calculation {
177 pub(super) fn new(info: &impl Info, objects: &Objects) -> Calculation {
178 Calculation {
179 ship: ItemResult::new(&objects.ship),
180 mode: objects.mode.as_ref().map(ItemResult::new),
181 items: objects.items.iter().map(ItemResult::new).collect(),
182 character: ItemResult::new(&objects.char),
183 buffs: objects.buffs.clone(),
184 outgoing: outgoing(info, objects),
185 violations: None,
186 }
187 }
188}