1use 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#[derive_const(PartialEq, Eq)]
12#[serde(rename_all = "camelCase")]
13#[builder(const)]
14#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
15pub struct Ethics {
16 power: EthicPowerAxis,
17 truth: EthicTruthAxis,
18}
19
20impl Ethics {
21 pub fn random() -> Self {
22 Self {
23 power: EthicPowerAxis::random(),
24 truth: EthicTruthAxis::random(),
25 }
26 }
27
28 #[inline]
29 pub const fn power(&self) -> EthicPowerAxis {
30 self.power
31 }
32
33 #[inline]
34 pub const fn truth(&self) -> EthicTruthAxis {
35 self.truth
36 }
37
38 #[inline]
39 pub const fn is_militarist(&self) -> bool {
40 self.power.is_militarist()
41 }
42
43 #[inline]
44 pub const fn is_fanatic_militarist(&self) -> bool {
45 self.power.is_fanatic_militarist()
46 }
47
48 #[inline]
49 pub const fn is_pacifist(&self) -> bool {
50 self.power.is_pacifist()
51 }
52
53 #[inline]
54 pub const fn is_fanatic_pacifist(&self) -> bool {
55 self.power.is_fanatic_pacifist()
56 }
57
58 #[inline]
59 pub const fn is_materialist(&self) -> bool {
60 self.truth.is_materialist()
61 }
62
63 #[inline]
64 pub const fn is_fanatic_materialist(&self) -> bool {
65 self.truth.is_fanatic_materialist()
66 }
67
68 #[inline]
69 pub const fn is_spiritualist(&self) -> bool {
70 self.truth.is_spiritualist()
71 }
72
73 #[inline]
74 pub const fn is_fanatic_spiritualist(&self) -> bool {
75 self.truth.is_fanatic_spiritualist()
76 }
77}
78
79impl From<EthicPowerAxis> for Ethics {
80 fn from(power: EthicPowerAxis) -> Self {
81 Self {
82 power,
83 truth: EthicTruthAxis::random(),
84 }
85 }
86}
87
88impl From<EthicTruthAxis> for Ethics {
89 fn from(truth: EthicTruthAxis) -> Self {
90 Self {
91 power: EthicPowerAxis::random(),
92 truth,
93 }
94 }
95}
96
97#[derive(Clone, Copy, Debug, EnumIs, Deserialize, Serialize, VariantArray)]
98#[derive_const(PartialEq, Eq)]
99#[serde(rename_all = "kebab-case")]
100#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
101pub enum EthicPowerAxis {
102 Militarist,
103 FanaticMilitarist,
104 Pacifist,
105 FanaticPacifist,
106}
107
108impl EthicPowerAxis {
109 pub fn random() -> Self {
110 Self::VARIANTS
111 .choose_weighted(&mut rand::rng(), |ethic| {
112 match ethic {
113 Self::Militarist | Self::Pacifist => 4u8,
114 Self::FanaticMilitarist | Self::FanaticPacifist => 1u8,
115 }
116 })
117 .copied()
118 .expect("`Self::VARIANTS` should never be empty")
119 }
120
121 pub const fn is_fanatic(&self) -> bool {
123 matches!(self, Self::FanaticMilitarist | Self::FanaticPacifist)
124 }
125
126 pub const fn is_militarist_variant(&self) -> bool {
128 matches!(self, Self::Militarist | Self::FanaticMilitarist)
129 }
130
131 pub const fn is_pacifist_variant(&self) -> bool {
133 matches!(self, Self::Pacifist | Self::FanaticPacifist)
134 }
135
136 pub const fn is_same_variant(&self, other: Self) -> bool {
137 (self.is_militarist_variant() && other.is_militarist_variant())
138 || (self.is_pacifist_variant() && other.is_pacifist_variant())
139 }
140}
141
142#[derive(Clone, Copy, Debug, EnumIs, Deserialize, Serialize, VariantArray)]
143#[derive_const(PartialEq, Eq)]
144#[serde(rename_all = "kebab-case")]
145#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
146pub enum EthicTruthAxis {
147 Materialist,
148 FanaticMaterialist,
149 Spiritualist,
150 FanaticSpiritualist,
151}
152
153impl EthicTruthAxis {
154 pub fn random() -> Self {
155 Self::VARIANTS
156 .choose_weighted(&mut rand::rng(), |ethic| {
157 match ethic {
158 Self::Materialist | Self::Spiritualist => 4u8,
159 Self::FanaticMaterialist | Self::FanaticSpiritualist => 1u8,
160 }
161 })
162 .copied()
163 .expect("`Self::VARIANTS` should never be empty")
164 }
165
166 pub const fn is_fanatic(&self) -> bool {
168 matches!(self, Self::FanaticMaterialist | Self::FanaticSpiritualist)
169 }
170
171 pub const fn is_materialist_variant(&self) -> bool {
173 matches!(self, Self::Materialist | Self::FanaticMaterialist)
174 }
175
176 pub const fn is_spiritualist_variant(&self) -> bool {
178 matches!(self, Self::Spiritualist | Self::FanaticSpiritualist)
179 }
180
181 pub const fn is_same_variant(&self, other: Self) -> bool {
182 (self.is_materialist_variant() && other.is_materialist_variant())
183 || (self.is_spiritualist_variant() && other.is_spiritualist_variant())
184 }
185}