lib_efo/entity/
implementations.rs

1//! Implementation of all needed traits for the Entity struct
2mod from_impl;
3use std::hash::Hash;
4
5use crate::{
6    Displayable,
7    entity::Entity,
8    epoch::{EpochInfo, epoch_traits::Diffable},
9    stats::{self, Symbols},
10};
11use colored::*;
12use uuid::Uuid; // [3]  - colored-rs examples
13mod accesors;
14mod methods;
15
16// ----------  Implementation ----------
17impl Displayable for Entity {
18    // Detailed multi-line view (used e.g. in logs)
19    fn print_full(&self, epoch_info: &EpochInfo) {
20        println!("{}", self.to_pretty_tree(epoch_info),);
21        if let Ok(c) = self.stats_to_table() {
22            println!("{c}");
23        }
24    }
25
26    /// One-liner used for auto-generation of `Vec<T>` displays
27    // TODO: URGENT: Change this display
28    fn oneline_display(&self) -> String {
29        let capital = self
30            .metadata
31            .capital
32            .as_ref()
33            .map(|c| format!("Capital:  {}  ", c.to_symbol().blue()))
34            .unwrap_or_default();
35
36        let governor = self
37            .metadata
38            .governor
39            .as_ref()
40            .map(|g| format!("Governor:  {}", g.to_symbol().blue()))
41            .unwrap_or_default();
42
43        let prestige = if *self.metadata.prestige > 0 {
44            format!(" {:2}{}", self.metadata.prestige, " ".yellow())
45        } else {
46            String::new()
47        };
48
49        // ---- build the two lines ----
50        let line1 = format!(
51            "├──┬─ {} {:23} {} ──────> {}     {}",
52            self.id.to_string().split_at(7).0.blue(),
53            self.name.green(),
54            self.entity_type.to_symbol(),
55            self.metadata.position.to_symbol(),
56            self.duration.to_symbol().yellow(),
57        );
58
59        let (junction, line3) = if !capital.is_empty() | !governor.is_empty() {
60            ("├", format!("│  └─ {}{}\n", capital, governor,))
61        } else {
62            ("└", "".to_string())
63        };
64        let line2 = format!(
65            "│  {}─ Faction: {} │  Effect: {} {},  Stats: {}{}",
66            junction,
67            self.metadata.faction.to_symbol(),
68            self.effect_nature.to_symbol(),
69            self.effect_bounds.to_symbol(),
70            self.stats.to_symbol(),
71            prestige,
72        );
73
74        format!("{}\n{}\n{}│", line1, line2, line3)
75    }
76}
77
78/// Short utility to make a symbol for an entity from it's Uuid
79fn uuid_to_symbol(id: Uuid, epoch_info: &EpochInfo, e_type: &stats::EntityType) -> String {
80    epoch_info
81        .find_entity_strict(id, Some(*e_type))
82        .map(|e| e.to_symbol())
83        .unwrap_or(format!(
84            "{}{} is missing {}",
85            " ".red(),
86            id.to_symbol().red(),
87            e_type.clone().to_shortest().blue()
88        ))
89}
90
91// impl Entity {
92//     /// Create a new Event
93//     fn new_event(name: String, description: String){}
94// }
95
96/// Replace a statistic in `stats` with the value from `pair`.
97///
98/// This function performs a direct overwrite: the existing value is
99/// discarded and the new value from `pair` is written in its place.
100#[inline]
101fn overwrite_stat(
102    stats: &mut stats::OverallStats,
103    pair: stats::StatPair,
104    delta: stats::Modification,
105) {
106    match delta {
107        stats::Modification::Delta => {
108            let affected_stat = stats.get_field_mut(&pair.stat);
109            let current_value = *affected_stat;
110            *affected_stat = stats::GenericStat(current_value.saturating_add(*pair.value));
111        }
112        stats::Modification::Replace => {
113            let affected_stat = stats.get_field_mut(&pair.stat);
114            *affected_stat = pair.value;
115        }
116        stats::Modification::Delete => {
117            let affected_stat = stats.get_field_mut(&pair.stat);
118            *affected_stat = stats::GenericStat::default();
119        }
120    }
121}
122
123/// Compare a field on `self` with the same field on `other`.
124/// If they are equal → `None`, otherwise → the value from `other`.
125macro_rules! diff_fields {
126    // Two arguments: the two objects you want to compare
127    ($self:ident, $other:ident, $( $field:ident ),* $(,)?) => {
128        $(
129            let $field = if $self.$field == $other.$field {
130                None
131            } else {
132                $other.$field.clone()
133            };
134        )*
135    };
136}
137impl Diffable for Entity {
138    fn delta(&self, other: &Self) -> Self {
139        let name = if self.name == other.name {
140            self.name.clone()
141        } else {
142            format!("{}->{}", self.name, other.name)
143        };
144        Self {
145            name,
146            stats: self.stats.clone() - other.stats.clone(),
147            temp_stats: self.temp_stats.delta(&other.temp_stats),
148            metadata: self.metadata.delta(&other.metadata),
149            entity_type: other.entity_type,
150            duration: other.duration.clone(),
151            effect_nature: other.effect_nature.clone(),
152            effect_bounds: other.effect_bounds.clone(),
153            id: Uuid::new_v4(),
154            description: other.description.clone(),
155        }
156    }
157}
158
159impl Diffable for Option<stats::OverallStats> {
160    fn delta(&self, other: &Self) -> Self {
161        match (self, other) {
162            (None, None) => None,
163            (None, Some(a)) => Some(a.clone()),
164            (Some(a), None) => Some(a.clone()),
165            (Some(a), Some(b)) => Some(a.clone() - b.clone()),
166        }
167    }
168}
169
170impl Diffable for stats::MetaStats {
171    fn delta(&self, other: &Self) -> Self {
172        diff_fields!(self, other, capital, governor);
173        Self {
174            position: self.position.clone() - other.position.clone(),
175            capital,
176            governor,
177            faction: {
178                match (self.faction.as_ref(), other.faction.as_ref()) {
179                    (None, None) => None,
180                    (None, Some(b)) => Some(*b),
181                    (Some(a), None) => Some(*a),
182                    (Some(_), Some(b)) => Some(*b),
183                }
184            },
185            links: self
186                .links
187                .clone()
188                .into_iter()
189                .filter(|t1| other.links.iter().any(|t2| t1 == t2))
190                .collect(),
191            prestige: self.prestige - other.prestige,
192            reach: stats::Reach::None,
193        }
194    }
195}
196
197impl stats::Symbols for Entity {
198    fn to_symbol(&self) -> String {
199        format!(
200            "{} {} {}",
201            self.entity_type.to_symbol().blue(),
202            self.id.to_symbol().blue(),
203            self.name
204        )
205    }
206}
207
208impl stats::Symbols for Uuid {
209    fn to_symbol(&self) -> String {
210        format!("󰻾[{}]", self.to_string().split_at(7).0)
211    }
212
213    fn to_shortest(&self) -> String {
214        self.to_string().split_at(7).0.to_string()
215    }
216}
217
218impl Hash for Entity {
219    /// Massive speedup at the cost of collision on updates, making eq for finding but not true equality
220    /// However a .deep_eq() should be used for this
221    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
222        // self.name.hash(state);
223        // self.description.hash(state);
224        self.id.hash(state);
225        // self.stats.hash(state);
226        // self.temp_stats.hash(state);
227        // self.metadata.hash(state);
228        // self.entity_type.hash(state);
229        // self.duration.hash(state);
230        // self.effect_nature.hash(state);
231        // self.effect_bounds.hash(state);
232    }
233}
234
235impl PartialEq for Entity {
236    /// Time save and clash if not .deep_eq
237    fn eq(&self, other: &Self) -> bool {
238        // self.name == other.name
239        //     && self.description == other.description
240        self.id == other.id
241        // && self.stats == other.stats
242        // && self.temp_stats == other.temp_stats
243        // && self.metadata == other.metadata
244        // && self.entity_type == other.entity_type
245        // && self.duration == other.duration
246        // && self.effect_nature == other.effect_nature
247        // && self.effect_bounds == other.effect_bounds
248    }
249}