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#[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
106impl Default for EthicPowerAxis {
107 fn default() -> Self {
108 Self::random()
109 }
110}
111
112#[derive(Clone, Copy, Debug, EnumIs, PartialEq, Eq, Deserialize, Serialize, VariantArray)]
113#[serde(rename_all = "kebab-case")]
114pub enum EthicTruthAxis {
115 Materialist,
116 FanaticMaterialist,
117 Spiritualist,
118 FanaticSpiritualist,
119}
120
121impl EthicTruthAxis {
122 pub fn random() -> Self {
123 Self::VARIANTS
124 .choose_weighted(&mut rand::rng(), |ethic| {
125 match ethic {
126 Self::Materialist | Self::Spiritualist => 4u8,
127 Self::FanaticMaterialist | Self::FanaticSpiritualist => 1u8,
128 }
129 })
130 .copied()
131 .expect("`Self::VARIANTS` should never be empty")
132 }
133}
134
135impl Default for EthicTruthAxis {
136 fn default() -> Self {
137 Self::random()
138 }
139}