Skip to main content

nil_core/
ruler.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::ethic::Ethics;
5use crate::npc::bot::{Bot, BotId};
6use crate::npc::precursor::{Precursor, PrecursorId};
7use crate::player::{Player, PlayerId};
8use crate::resources::Resources;
9use crate::resources::gold::Gold;
10use crate::resources::influence::Influence;
11use derive_more::{TryUnwrap, Unwrap};
12use serde::{Deserialize, Serialize};
13use std::{cmp, fmt, mem};
14use strum::EnumIs;
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, EnumIs)]
17#[serde(tag = "kind", rename_all = "kebab-case")]
18#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
19pub enum Ruler {
20  Bot { id: BotId },
21  Player { id: PlayerId },
22  Precursor { id: PrecursorId },
23}
24
25impl Ruler {
26  #[inline]
27  pub fn bot(&self) -> Option<&BotId> {
28    if let Self::Bot { id } = self { Some(id) } else { None }
29  }
30
31  #[inline]
32  pub fn player(&self) -> Option<&PlayerId> {
33    if let Self::Player { id } = self { Some(id) } else { None }
34  }
35
36  #[inline]
37  pub fn precursor(&self) -> Option<PrecursorId> {
38    if let Self::Precursor { id } = self { Some(*id) } else { None }
39  }
40
41  pub fn is_bot_and<F>(&self, f: F) -> bool
42  where
43    F: FnOnce(&BotId) -> bool,
44  {
45    self.bot().is_some_and(f)
46  }
47
48  pub fn is_player_and<F>(&self, f: F) -> bool
49  where
50    F: FnOnce(&PlayerId) -> bool,
51  {
52    self.player().is_some_and(f)
53  }
54
55  pub fn is_precursor_and<F>(&self, f: F) -> bool
56  where
57    F: FnOnce(PrecursorId) -> bool,
58  {
59    self.precursor().is_some_and(f)
60  }
61}
62
63impl AsRef<str> for Ruler {
64  fn as_ref(&self) -> &str {
65    match self {
66      Self::Bot { id } => id.as_str(),
67      Self::Player { id } => id.as_str(),
68      Self::Precursor { id } => id.as_ref(),
69    }
70  }
71}
72
73impl fmt::Display for Ruler {
74  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75    match self {
76      Self::Bot { id } => id.fmt(f),
77      Self::Player { id } => id.fmt(f),
78      Self::Precursor { id } => id.fmt(f),
79    }
80  }
81}
82
83impl From<&Bot> for Ruler {
84  fn from(bot: &Bot) -> Self {
85    Self::Bot { id: bot.id() }
86  }
87}
88
89impl From<BotId> for Ruler {
90  fn from(id: BotId) -> Self {
91    Self::Bot { id }
92  }
93}
94
95impl From<&BotId> for Ruler {
96  fn from(id: &BotId) -> Self {
97    Self::Bot { id: id.clone() }
98  }
99}
100
101impl From<&Player> for Ruler {
102  fn from(player: &Player) -> Self {
103    Self::Player { id: player.id() }
104  }
105}
106
107impl From<PlayerId> for Ruler {
108  fn from(id: PlayerId) -> Self {
109    Self::Player { id }
110  }
111}
112
113impl From<&PlayerId> for Ruler {
114  fn from(id: &PlayerId) -> Self {
115    Self::Player { id: id.clone() }
116  }
117}
118
119impl From<&dyn Precursor> for Ruler {
120  fn from(precursor: &dyn Precursor) -> Self {
121    Self::Precursor { id: precursor.id() }
122  }
123}
124
125impl<T: Precursor> From<&T> for Ruler {
126  fn from(precursor: &T) -> Self {
127    Self::Precursor { id: precursor.id() }
128  }
129}
130
131impl From<PrecursorId> for Ruler {
132  fn from(id: PrecursorId) -> Self {
133    Self::Precursor { id }
134  }
135}
136
137impl From<RulerRef<'_>> for Ruler {
138  fn from(ruler: RulerRef<'_>) -> Self {
139    match ruler {
140      RulerRef::Bot(bot) => Self::Bot { id: bot.id() },
141      RulerRef::Player(player) => Self::Player { id: player.id() },
142      RulerRef::Precursor(precursor) => Self::Precursor { id: precursor.id() },
143    }
144  }
145}
146
147impl From<RulerRefMut<'_>> for Ruler {
148  fn from(ruler: RulerRefMut<'_>) -> Self {
149    match ruler {
150      RulerRefMut::Bot(bot) => Self::Bot { id: bot.id() },
151      RulerRefMut::Player(player) => Self::Player { id: player.id() },
152      RulerRefMut::Precursor(precursor) => Self::Precursor { id: precursor.id() },
153    }
154  }
155}
156
157impl PartialOrd for Ruler {
158  fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
159    Some(self.cmp(other))
160  }
161}
162
163impl Ord for Ruler {
164  fn cmp(&self, other: &Self) -> cmp::Ordering {
165    match (self, other) {
166      (Self::Bot { id: a }, Self::Bot { id: b }) => a.cmp(b),
167      (Self::Player { id: a }, Self::Player { id: b }) => a.cmp(b),
168      (Self::Precursor { id: a }, Self::Precursor { id: b }) => a.cmp(b),
169      (Self::Bot { .. }, Self::Player { .. }) => cmp::Ordering::Less,
170      (Self::Bot { .. }, Self::Precursor { .. }) => cmp::Ordering::Greater,
171      (Self::Player { .. }, _) => cmp::Ordering::Greater,
172      (Self::Precursor { .. }, _) => cmp::Ordering::Less,
173    }
174  }
175}
176
177#[derive(EnumIs, TryUnwrap, Unwrap)]
178#[try_unwrap(ref)]
179#[unwrap(ref)]
180pub enum RulerRef<'a> {
181  Bot(&'a Bot),
182  Player(&'a Player),
183  Precursor(&'a dyn Precursor),
184}
185
186impl<'a> RulerRef<'a> {
187  pub fn ethics(&self) -> Option<&'a Ethics> {
188    match self {
189      Self::Bot(bot) => Some(bot.ethics()),
190      Self::Player(..) => None,
191      Self::Precursor(precursor) => Some(precursor.ethics()),
192    }
193  }
194
195  pub fn resources(&self) -> Resources {
196    match self {
197      Self::Bot(bot) => bot.resources(),
198      Self::Player(player) => player.resources(),
199      Self::Precursor(precursor) => precursor.resources(),
200    }
201  }
202
203  #[inline]
204  pub fn has_resources(&self, resources: Resources) -> bool {
205    self
206      .resources()
207      .checked_sub(resources)
208      .is_some()
209  }
210
211  pub fn gold(&self) -> Gold {
212    match self {
213      Self::Bot(bot) => bot.gold(),
214      Self::Player(player) => player.gold(),
215      Self::Precursor(precursor) => precursor.gold(),
216    }
217  }
218
219  pub fn influence(&self) -> Influence {
220    match self {
221      Self::Bot(bot) => bot.influence(),
222      Self::Player(player) => player.influence(),
223      Self::Precursor(precursor) => precursor.influence(),
224    }
225  }
226}
227
228impl<'a> From<&'a Bot> for RulerRef<'a> {
229  fn from(bot: &'a Bot) -> Self {
230    Self::Bot(bot)
231  }
232}
233
234impl<'a> From<&'a Player> for RulerRef<'a> {
235  fn from(player: &'a Player) -> Self {
236    Self::Player(player)
237  }
238}
239
240impl<'a> From<&'a dyn Precursor> for RulerRef<'a> {
241  fn from(precursor: &'a dyn Precursor) -> Self {
242    Self::Precursor(precursor)
243  }
244}
245
246#[derive(EnumIs, TryUnwrap, Unwrap)]
247#[try_unwrap(ref)]
248#[unwrap(ref)]
249pub enum RulerRefMut<'a> {
250  Bot(&'a mut Bot),
251  Player(&'a mut Player),
252  Precursor(&'a mut dyn Precursor),
253}
254
255impl<'a> RulerRefMut<'a> {
256  pub fn resources_mut(&'a mut self) -> &'a mut Resources {
257    match self {
258      Self::Bot(bot) => bot.resources_mut(),
259      Self::Player(player) => player.resources_mut(),
260      Self::Precursor(precursor) => precursor.resources_mut(),
261    }
262  }
263
264  pub fn take_resources(&mut self) -> Resources {
265    match self {
266      Self::Bot(bot) => mem::take(bot.resources_mut()),
267      Self::Player(player) => mem::take(player.resources_mut()),
268      Self::Precursor(precursor) => mem::take(precursor.resources_mut()),
269    }
270  }
271}
272
273impl<'a> From<&'a mut Bot> for RulerRefMut<'a> {
274  fn from(bot: &'a mut Bot) -> Self {
275    Self::Bot(bot)
276  }
277}
278
279impl<'a> From<&'a mut Player> for RulerRefMut<'a> {
280  fn from(player: &'a mut Player) -> Self {
281    Self::Player(player)
282  }
283}
284
285impl<'a> From<&'a mut dyn Precursor> for RulerRefMut<'a> {
286  fn from(precursor: &'a mut dyn Precursor) -> Self {
287    Self::Precursor(precursor)
288  }
289}