game_features/effector.rs
1use crate::*;
2use std::collections::HashMap;
3use std::hash::Hash;
4
5/// Holds the definitions of the stat effectors.
6#[derive(Debug, Clone, Serialize, Deserialize, new)]
7pub struct EffectorDefinitions<K, E: Hash + Eq> {
8 /// The definitions.
9 pub defs: HashMap<E, EffectorDefinition<K, E>>,
10}
11
12impl<K, E: Hash + Eq> Default for EffectorDefinitions<K, E> {
13 fn default() -> Self {
14 Self {
15 defs: HashMap::default(),
16 }
17 }
18}
19
20impl<K: Hash + Eq + Clone, E: Hash + Eq + Clone> From<Vec<EffectorDefinition<K, E>>>
21 for EffectorDefinitions<K, E>
22{
23 fn from(t: Vec<EffectorDefinition<K, E>>) -> Self {
24 let defs = t
25 .into_iter()
26 .map(|s| (s.key.clone(), s))
27 .collect::<HashMap<_, _>>();
28 Self::new(defs)
29 }
30}
31
32/// A collection of currently active effectors.
33#[derive(Debug, Clone, Serialize, Deserialize, new)]
34pub struct EffectorSet<E> {
35 /// The active effectors.
36 pub effectors: Vec<EffectorInstance<E>>,
37}
38
39impl<E> Default for EffectorSet<E> {
40 fn default() -> Self {
41 Self { effectors: vec![] }
42 }
43}
44
45impl<E: Hash + Eq> EffectorSet<E> {
46 /// Applies the effects of this effector to the provided `StatSet`.
47 /// The delta time is used when using effectors that apply directly to
48 /// the base stat value. (WIP)
49 pub fn apply_to<K: Eq + Hash>(
50 self: &Self,
51 effector_defs: &EffectorDefinitions<K, E>,
52 stat_set: &mut StatSet<K>,
53 _delta_time: f32,
54 ) {
55 for s in stat_set.stats.values_mut() {
56 let mut new_value = s.value;
57 let mut multiplicative_multiplier = 1.0;
58 let mut additive_multiplier = 0.0;
59 let mut additive = 0.0;
60 // find effectors affecting this stat
61 for e in self.effectors.iter() {
62 let def = effector_defs
63 .defs
64 .get(&e.effector_key)
65 .expect("Tried to get unknown stat key.");
66
67 // Algo:
68 // - Apply all multiplicative multipliers
69 // - Apply all additive multipliers
70 // - Apply all additives
71
72 // look into the effect of each effector
73 for (key, ty) in def.effects.iter() {
74 // if any matches
75 if *key == s.key {
76 // Apply Effector
77 match ty {
78 EffectorType::Additive(v) => additive += v,
79 EffectorType::AdditiveMultiplier(v) => additive_multiplier += v,
80 EffectorType::MultiplicativeMultiplier(v) => {
81 multiplicative_multiplier *= v
82 }
83 }
84 }
85 }
86 }
87 let multiplier = multiplicative_multiplier + additive_multiplier;
88 new_value += additive;
89 new_value *= multiplier;
90 s.value_with_effectors = new_value;
91 }
92 }
93}
94
95/// The definition of a stat effector.
96/// This modifies temporarily the value of a stat.
97#[derive(Debug, Clone, Serialize, Deserialize, new)]
98pub struct EffectorDefinition<K, E> {
99 /// The key of the effector.
100 pub key: E,
101 /// The duration of the effector.
102 /// None means that it does not expire.
103 /// Some(0) means that it is applied only once.
104 /// Some(n) means that it is applied for n seconds.
105 pub duration: Option<f64>,
106 /// The effects that cause this effector.
107 /// Note that effectors can only cause effects on a single stat.
108 /// To affect multiple stats, create multiple effectors.
109 // TODO consider using only a single element here? It almost never happens that
110 // we want to apply multiple changes to the same stat.
111 pub effects: Vec<(K, EffectorType)>,
112}
113
114/// The way this effector modifies the stat.
115#[derive(Debug, Clone, Serialize, Deserialize, new)]
116pub enum EffectorType {
117 /// Adds a value to the base value of the stat.
118 Additive(f64),
119 /// Multiplies the stat by a value.
120 /// Stacks additively with other multipliers affecting this same stat.
121 AdditiveMultiplier(f64),
122 /// Multiplies the stat by a value.
123 /// Stacks multiplicatively with other multipliers affecting this same stat.
124 MultiplicativeMultiplier(f64),
125}
126
127/// An active instance of an effector.
128#[derive(Debug, Clone, Serialize, Deserialize, new)]
129pub struct EffectorInstance<E> {
130 /// The key of the effector.
131 pub effector_key: E,
132 /// The time before this effector expires.
133 pub disable_in: Option<f64>,
134}