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