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