Skip to main content

wowlab_loadout/
apply.rs

1use wowlab_types::{
2    data::{TraitSelection, TraitTreeFlat, TraitTreeWithSelections},
3    sim::IntMap,
4};
5
6use crate::DecodedTraitLoadout;
7
8/// Applies decoded positional selections to a trait tree using `all_node_ids` as the wire order.
9#[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;