Skip to main content

nil_core/
ethic.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use bon::Builder;
5use rand::seq::IndexedRandom;
6use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8use strum::{EnumIs, VariantArray};
9
10#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
11#[serde(rename_all = "camelCase")]
12#[builder(const)]
13pub struct Ethics {
14  power: EthicPowerAxis,
15  truth: EthicTruthAxis,
16}
17
18impl Ethics {
19  pub fn random() -> Self {
20    Self {
21      power: EthicPowerAxis::random(),
22      truth: EthicTruthAxis::random(),
23    }
24  }
25
26  #[inline]
27  pub const fn power(&self) -> EthicPowerAxis {
28    self.power
29  }
30
31  #[inline]
32  pub const fn truth(&self) -> EthicTruthAxis {
33    self.truth
34  }
35
36  #[inline]
37  pub const fn is_militarist(&self) -> bool {
38    self.power.is_militarist()
39  }
40
41  #[inline]
42  pub const fn is_fanatic_militarist(&self) -> bool {
43    self.power.is_fanatic_militarist()
44  }
45
46  #[inline]
47  pub const fn is_pacifist(&self) -> bool {
48    self.power.is_pacifist()
49  }
50
51  #[inline]
52  pub const fn is_fanatic_pacifist(&self) -> bool {
53    self.power.is_fanatic_pacifist()
54  }
55
56  #[inline]
57  pub const fn is_materialist(&self) -> bool {
58    self.truth.is_materialist()
59  }
60
61  #[inline]
62  pub const fn is_fanatic_materialist(&self) -> bool {
63    self.truth.is_fanatic_materialist()
64  }
65
66  #[inline]
67  pub const fn is_spiritualist(&self) -> bool {
68    self.truth.is_spiritualist()
69  }
70
71  #[inline]
72  pub const fn is_fanatic_spiritualist(&self) -> bool {
73    self.truth.is_fanatic_spiritualist()
74  }
75}
76
77impl Default for Ethics {
78  fn default() -> Self {
79    Self::random()
80  }
81}
82
83#[derive(Clone, Copy, Debug, EnumIs, PartialEq, Eq, Deserialize, Serialize, VariantArray)]
84#[serde(rename_all = "kebab-case")]
85pub enum EthicPowerAxis {
86  Militarist,
87  FanaticMilitarist,
88  Pacifist,
89  FanaticPacifist,
90}
91
92impl EthicPowerAxis {
93  pub fn random() -> Self {
94    Self::VARIANTS
95      .choose_weighted(&mut rand::rng(), |ethic| {
96        match ethic {
97          Self::Militarist | Self::Pacifist => 4u8,
98          Self::FanaticMilitarist | Self::FanaticPacifist => 1u8,
99        }
100      })
101      .copied()
102      .expect("`Self::VARIANTS` should never be empty")
103  }
104
105  /// Whether this ethic is [`EthicPowerAxis::Militarist`] or [`EthicPowerAxis::FanaticMilitarist`].
106  pub fn is_militarist_variant(&self) -> bool {
107    matches!(self, Self::Militarist | Self::FanaticMilitarist)
108  }
109
110  /// Whether this ethic is [`EthicPowerAxis::Pacifist`] or [`EthicPowerAxis::FanaticPacifist`].
111  pub fn is_pacifist_variant(&self) -> bool {
112    matches!(self, Self::Pacifist | Self::FanaticPacifist)
113  }
114}
115
116impl Default for EthicPowerAxis {
117  fn default() -> Self {
118    Self::random()
119  }
120}
121
122#[derive(Clone, Copy, Debug, EnumIs, PartialEq, Eq, Deserialize, Serialize, VariantArray)]
123#[serde(rename_all = "kebab-case")]
124pub enum EthicTruthAxis {
125  Materialist,
126  FanaticMaterialist,
127  Spiritualist,
128  FanaticSpiritualist,
129}
130
131impl EthicTruthAxis {
132  pub fn random() -> Self {
133    Self::VARIANTS
134      .choose_weighted(&mut rand::rng(), |ethic| {
135        match ethic {
136          Self::Materialist | Self::Spiritualist => 4u8,
137          Self::FanaticMaterialist | Self::FanaticSpiritualist => 1u8,
138        }
139      })
140      .copied()
141      .expect("`Self::VARIANTS` should never be empty")
142  }
143
144  /// Whether this ethic is [`EthicTruthAxis::Materialist`] or [`EthicTruthAxis::FanaticMaterialist`].
145  pub fn is_materialist_variant(&self) -> bool {
146    matches!(self, Self::Materialist | Self::FanaticMaterialist)
147  }
148
149  /// Whether this ethic is [`EthicTruthAxis::Spiritualist`] or [`EthicTruthAxis::FanaticSpiritualist`].
150  pub fn is_spiritualist_variant(&self) -> bool {
151    matches!(self, Self::Spiritualist | Self::FanaticSpiritualist)
152  }
153}
154
155impl Default for EthicTruthAxis {
156  fn default() -> Self {
157    Self::random()
158  }
159}