Skip to main content

nil_core/world/player/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4#[cfg(test)]
5mod tests;
6
7use crate::capital::Capital;
8use crate::city::City;
9use crate::error::{Error, Result};
10use crate::military::Military;
11use crate::military::maneuver::ManeuverDirection;
12use crate::player::{Player, PlayerId, PlayerManager, PlayerStatus};
13use crate::resources::maintenance::Maintenance;
14use crate::ruler::Ruler;
15use crate::world::World;
16
17impl World {
18  #[inline]
19  pub fn player_manager(&self) -> &PlayerManager {
20    &self.player_manager
21  }
22
23  #[inline]
24  pub fn player(&self, id: &PlayerId) -> Result<&Player> {
25    self.player_manager.player(id)
26  }
27
28  #[inline]
29  pub(crate) fn player_mut(&mut self, id: &PlayerId) -> Result<&mut Player> {
30    self.player_manager.player_mut(id)
31  }
32
33  pub fn players(&self) -> impl Iterator<Item = &Player> {
34    self.player_manager.players()
35  }
36
37  #[inline]
38  pub fn get_player_maintenance(&self, player: &PlayerId) -> Result<Maintenance> {
39    self.get_maintenance(player)
40  }
41
42  pub fn get_player_military(&self, player: &PlayerId) -> Result<Military> {
43    let ruler = Ruler::from(player);
44    let coords = self.continent.coords_of(player);
45    let mut military = self.military.intersection(coords)?;
46
47    // Ensures that maneuvers whose origin or destination
48    // is not among the player's coords are also included.
49    for maneuver in self.military.maneuvers() {
50      if !military.has_maneuver(maneuver.id())
51        && self
52          .military
53          .army(maneuver.army())?
54          .owner()
55          .eq(&ruler)
56      {
57        military.insert_maneuver(maneuver.clone());
58      }
59    }
60
61    military.retain_maneuvers(|maneuver| {
62      // Should not include foreign armies returning home.
63      if let ManeuverDirection::Returning = maneuver.direction() {
64        self
65          .military
66          .army(maneuver.army())
67          .is_ok_and(|army| army.is_owned_by(&ruler))
68      } else {
69        true
70      }
71    });
72
73    Ok(military)
74  }
75
76  #[inline]
77  pub fn has_player(&self, id: &PlayerId) -> bool {
78    self.player_manager.has(id)
79  }
80
81  pub fn has_any_active_player(&self) -> bool {
82    self
83      .player_manager
84      .players()
85      .any(Player::is_active)
86  }
87
88  pub fn set_player_status(&mut self, id: &PlayerId, status: PlayerStatus) -> Result<()> {
89    self.player_manager.player_mut(id)?.status = status;
90    self.emit_player(id.clone())?;
91    Ok(())
92  }
93
94  pub fn spawn_player(&mut self, mut player: Player) -> Result<()> {
95    let id = player.id();
96    if self.has_player(&id) {
97      Err(Error::PlayerAlreadySpawned(id))
98    } else {
99      let (coord, field) = self.find_spawn_point()?;
100      *field = City::builder(coord)
101        .name(&*id)
102        .owner(&id)
103        .build()
104        .into();
105
106      player.status = PlayerStatus::Active;
107      player.capital = Capital::new(coord);
108      self.player_manager.manage(player)?;
109
110      self.emit_public_city(coord)?;
111
112      Ok(())
113    }
114  }
115}