1use wowlab_types::{
2 data::{TraitSelection, TraitTreeFlat, TraitTreeWithSelections},
3 sim::IntMap,
4};
5
6use crate::DecodedTraitLoadout;
7
8#[must_use]
10pub fn apply_decoded_traits(
11 tree: TraitTreeFlat,
12 decoded: &DecodedTraitLoadout,
13) -> TraitTreeWithSelections {
14 let node_by_id: IntMap<i32, _> = tree.nodes.iter().map(|n| (n.id, n)).collect();
15
16 let mut selections = Vec::new();
17
18 for (i, &node_id) in tree.all_node_ids.iter().enumerate() {
19 if let Some(tree_node) = node_by_id.get(&node_id) {
20 let decoded_node = decoded.nodes.get(i);
21
22 if decoded_node.is_none() && tree_node.granted_ranks <= 0 {
23 continue;
24 }
25
26 let purchased = decoded_node.is_some_and(|node| node.purchased);
27 let selected = decoded_node.is_some_and(|node| node.selected);
28 let ranks_purchased = decoded_node
29 .and_then(|node| node.ranks_purchased)
30 .map_or_else(
31 || {
32 if purchased {
33 tree_node.max_ranks
34 } else if selected || tree_node.granted_ranks > 0 {
35 tree_node.granted_ranks.max(1)
36 } else {
37 0
38 }
39 },
40 i32::from,
41 );
42
43 selections.push(TraitSelection {
44 node_id,
45 selected: selected || tree_node.granted_ranks > 0,
46 ranks_purchased,
47 choice_index: decoded_node.and_then(|node| node.choice_index),
48 });
49 }
50 }
51
52 TraitTreeWithSelections { tree, selections }
53}
54
55#[cfg(test)]
56#[path = "apply_tests.rs"]
57mod tests;