nil-core 0.7.17

Multiplayer strategy game
Documentation
// Copyright (C) Call of Nil contributors
// SPDX-License-Identifier: AGPL-3.0-only

mod academy;
mod prefecture;
mod stable;
mod workshop;

#[cfg(test)]
mod tests;

use crate::continent::coord::Coord;
use crate::continent::index::ContinentKey;
use crate::error::Result;
use crate::infrastructure::prelude::{BuildingId, BuildingLevel};
use crate::world::World;

impl World {
  /// Sets the level of a building.
  ///
  /// Does **NOT** emit any events.
  pub(crate) fn set_building_level(
    &mut self,
    key: impl ContinentKey,
    id: BuildingId,
    level: BuildingLevel,
  ) -> Result<()> {
    self
      .city_mut(key)?
      .infrastructure_mut()
      .building_mut(id)
      .set_level(level);

    Ok(())
  }

  pub fn toggle_building(&mut self, coord: Coord, id: BuildingId, enabled: bool) -> Result<()> {
    self
      .continent
      .city_mut(coord)?
      .infrastructure_mut()
      .building_mut(id)
      .toggle(enabled);

    self.emit_city(coord)?;

    Ok(())
  }
}

#[doc(hidden)]
#[macro_export]
macro_rules! decl_world_recruit_order_fn {
  ($building:ident) => {
    paste::paste! {
      impl World {
        pub fn [<add_ $building:snake _recruit_order>](
          &mut self,
          req: &[<$building RecruitOrderRequest>]
        ) -> Result<()> {
          let ruler = self.city(req.coord)?.owner().clone();
          let available_resources = self.ruler(&ruler)?.resources();

          let order = self
            .city_mut(req.coord)?
            .infrastructure_mut()
            .[<add_ $building:snake _recruit_order>](req, available_resources)?
            .clone();

          let mut ruler_ref = self.ruler_mut(&ruler)?;
          let resources = ruler_ref.resources_mut();
          *resources = resources
            .checked_sub(order.resources())
            .ok_or(Error::InsufficientResources)?;

          self.emit_ruler(&ruler)?;
          self.emit_city(req.coord)?;

          Ok(())
        }

        pub fn [<cancel_ $building:snake _recruit_order>](
          &mut self,
          coord: Coord,
          id: [<$building RecruitOrderId>]
        ) -> Result<()> {
          let city = self.city_mut(coord)?;
          let order = city
            .infrastructure_mut()
            .[<cancel_ $building:snake _recruit_order>](id);

          if let Some(order) = order {
            let ruler = city.owner().clone();
            let mut ruler_ref = self.ruler_mut(&ruler)?;
            let resources = ruler_ref.resources_mut();
            *resources += order.resources();

            self.emit_ruler(&ruler)?;
            self.emit_city(coord)?;
          }

          Ok(())
        }
      }
    }
  };
}