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  pub(crate) fn gold_mut(&mut self) -> &mut Gold {
103    &mut self.gold
104  }
105
106  #[inline]
107  pub fn influence(&self) -> Influence {
108    self.influence
109  }
110}
111
112#[derive(
113  Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Deserialize, Serialize,
114)]
115#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
116#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
117pub struct BotId(Arc<str>);
118
119impl Clone for BotId {
120  fn clone(&self) -> Self {
121    Self(Arc::clone(&self.0))
122  }
123}
124
125impl AsRef<str> for BotId {
126  fn as_ref(&self) -> &str {
127    self.0.as_str()
128  }
129}
130
131impl Deref for BotId {
132  type Target = str;
133
134  fn deref(&self) -> &Self::Target {
135    self.0.as_str()
136  }
137}
138
139impl Borrow<str> for BotId {
140  fn borrow(&self) -> &str {
141    self.0.as_str()
142  }
143}
144
145impl From<BotId> for String {
146  fn from(value: BotId) -> Self {
147    String::from(value.0.as_ref())
148  }
149}
150
151impl PartialEq<Ruler> for BotId {
152  fn eq(&self, other: &Ruler) -> bool {
153    if let Ruler::Bot { id } = other { self.eq(id) } else { false }
154  }
155}
156
157#[derive(Clone, Debug, Deserialize, Serialize)]
158#[serde(rename_all = "camelCase")]
159#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
160pub struct PublicBot {
161  id: BotId,
162}
163
164impl From<&Bot> for PublicBot {
165  fn from(bot: &Bot) -> Self {
166    Self { id: bot.id.clone() }
167  }
168}