Skip to main content

nil_core/world/npc/
bot.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::city::City;
5use crate::error::Result;
6use crate::infrastructure::Infrastructure;
7use crate::npc::bot::{Bot, BotId, BotManager};
8use crate::with_random_level;
9use crate::world::World;
10use num_traits::ToPrimitive;
11use tap::Conv;
12
13impl World {
14  #[inline]
15  pub fn bot_manager(&self) -> &BotManager {
16    &self.bot_manager
17  }
18
19  #[inline]
20  pub fn bot(&self, id: &BotId) -> Result<&Bot> {
21    self.bot_manager.bot(id)
22  }
23
24  #[inline]
25  pub(crate) fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
26    self.bot_manager.bot_mut(id)
27  }
28
29  pub fn bots(&self) -> impl Iterator<Item = &Bot> {
30    self.bot_manager.bots()
31  }
32
33  pub(crate) fn spawn_bot(
34    &mut self,
35    id: impl Into<BotId>,
36    infrastructure: Infrastructure,
37  ) -> Result<BotId> {
38    let id: BotId = id.into();
39    self.bot_manager.manage(id.clone())?;
40
41    let (coord, field) = self.find_spawn_point()?;
42
43    *field = City::builder(coord)
44      .name(id.as_ref())
45      .owner(id.clone())
46      .infrastructure(infrastructure)
47      .build()
48      .into();
49
50    Ok(id)
51  }
52
53  pub(crate) fn spawn_bots(&mut self) -> Result<()> {
54    let size = self.continent.size();
55    let density = self.config().bot_density();
56    let amount = (f64::from(size) * density)
57      .floor()
58      .max(0.0)
59      .to_usize()
60      .unwrap_or_else(|| usize::from(size).saturating_mul(2));
61
62    let advanced_start_ratio = self
63      .config
64      .bot_advanced_start_ratio()
65      .conv::<f64>();
66
67    for name in nil_namegen::generate(amount) {
68      let infrastructure = if rand::random::<f64>() > advanced_start_ratio {
69        Infrastructure::default()
70      } else {
71        Infrastructure::builder()
72          .farm(with_random_level!(Farm, 1, 10))
73          .iron_mine(with_random_level!(IronMine, 1, 10))
74          .prefecture(with_random_level!(Prefecture, 1, 5))
75          .quarry(with_random_level!(Quarry, 1, 10))
76          .sawmill(with_random_level!(Sawmill, 1, 10))
77          .silo(with_random_level!(Silo, 10, 15))
78          .warehouse(with_random_level!(Warehouse, 10, 15))
79          .build()
80      };
81
82      self.spawn_bot(name, infrastructure)?;
83    }
84
85    Ok(())
86  }
87}