Skip to main content

nil_core/npc/bot/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::capital::{Capital, PublicCapital};
5use crate::error::{Error, Result};
6use crate::ethic::Ethics;
7use crate::resources::Resources;
8use crate::resources::gold::Gold;
9use crate::resources::influence::Influence;
10use crate::ruler::Ruler;
11use derive_more::{Display, From, Into};
12use serde::{Deserialize, Serialize};
13use std::borrow::{Borrow, Cow};
14use std::collections::HashMap;
15use std::ops::Deref;
16use std::sync::Arc;
17
18#[derive(Clone, Debug, Default, Deserialize, Serialize)]
19#[serde(rename_all = "camelCase")]
20pub struct BotManager(HashMap<BotId, Bot>);
21
22impl BotManager {
23  pub(crate) fn manage(&mut self, id: BotId) -> Result<()> {
24    if self.0.contains_key(&id) {
25      return Err(Error::BotAlreadySpawned(id));
26    }
27
28    self.0.insert(id.clone(), Bot::new(id));
29
30    Ok(())
31  }
32
33  pub fn bot(&self, id: &BotId) -> Result<&Bot> {
34    self
35      .0
36      .get(id)
37      .ok_or_else(|| Error::BotNotFound(id.clone()))
38  }
39
40  pub(crate) fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
41    self
42      .0
43      .get_mut(id)
44      .ok_or_else(|| Error::BotNotFound(id.clone()))
45  }
46
47  pub fn bots(&self) -> impl Iterator<Item = &Bot> {
48    self.0.values()
49  }
50}
51
52#[derive(Clone, Debug, Deserialize, Serialize)]
53#[serde(rename_all = "camelCase")]
54#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
55pub struct Bot {
56  id: BotId,
57  pub(crate) ethics: Ethics,
58  pub(crate) capital: Capital,
59  pub(crate) resources: Resources,
60  pub(crate) gold: Gold,
61  pub(crate) influence: Influence,
62}
63
64impl Bot {
65  pub fn new(id: BotId) -> Self {
66    Self {
67      id,
68      ethics: Ethics::random(),
69      capital: Capital::default(),
70      resources: Resources::BOT,
71      gold: Gold::MIN,
72      influence: Influence::MIN,
73    }
74  }
75
76  #[inline]
77  pub fn id(&self) -> BotId {
78    self.id.clone()
79  }
80
81  #[inline]
82  pub fn ethics(&self) -> Ethics {
83    self.ethics
84  }
85
86  #[inline]
87  pub fn capital(&self) -> &Capital {
88    &self.capital
89  }
90
91  #[inline]
92  pub fn resources(&self) -> Resources {
93    self.resources
94  }
95
96  #[inline]
97  pub fn gold(&self) -> Gold {
98    self.gold
99  }
100
101  #[inline]
102  pub fn influence(&self) -> Influence {
103    self.influence
104  }
105}
106
107#[derive(
108  Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Deserialize, Serialize,
109)]
110#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
111#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
112pub struct BotId(Arc<str>);
113
114impl Clone for BotId {
115  fn clone(&self) -> Self {
116    Self(Arc::clone(&self.0))
117  }
118}
119
120impl AsRef<str> for BotId {
121  fn as_ref(&self) -> &str {
122    self.0.as_str()
123  }
124}
125
126impl Deref for BotId {
127  type Target = str;
128
129  fn deref(&self) -> &Self::Target {
130    self.0.as_str()
131  }
132}
133
134impl Borrow<str> for BotId {
135  fn borrow(&self) -> &str {
136    self.0.as_str()
137  }
138}
139
140impl From<BotId> for String {
141  fn from(value: BotId) -> Self {
142    String::from(value.0.as_ref())
143  }
144}
145
146impl PartialEq<Ruler> for BotId {
147  fn eq(&self, other: &Ruler) -> bool {
148    if let Ruler::Bot { id } = other { self.eq(id) } else { false }
149  }
150}
151
152#[derive(Clone, Debug, Deserialize, Serialize)]
153#[serde(rename_all = "camelCase")]
154#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
155pub struct PublicBot {
156  id: BotId,
157  capital: PublicCapital,
158}
159
160impl From<&Bot> for PublicBot {
161  fn from(bot: &Bot) -> Self {
162    Self {
163      id: bot.id.clone(),
164      capital: PublicCapital::from(&bot.capital),
165    }
166  }
167}