1mod 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; mod accesors;
14mod methods;
15
16impl Displayable for Entity {
18 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 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 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
78fn 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#[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
123macro_rules! diff_fields {
126 ($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 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
222 self.id.hash(state);
225 }
233}
234
235impl PartialEq for Entity {
236 fn eq(&self, other: &Self) -> bool {
238 self.id == other.id
241 }
249}