essences/
vassals.rs

1use chrono::Utc;
2use strum_macros::{Display, EnumString};
3
4use crate::prelude::*;
5
6use crate::currency::CurrencyUnit;
7
8#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
9pub struct Suzerain {
10    pub character_id: Uuid,
11    pub username: String,
12    pub photo_url: Option<String>,
13    pub loyalty: i64,
14    pub last_claimed_reward_at: chrono::DateTime<chrono::Utc>,
15    pub last_claimed_power: i64,
16    pub current_power: i64,
17    pub current_reward: Vec<CurrencyUnit>,
18    pub created_at: chrono::DateTime<chrono::Utc>,
19}
20
21impl Suzerain {
22    pub fn claim_reward(&mut self, claim_time: chrono::DateTime<chrono::Utc>) {
23        self.current_reward = vec![];
24        self.last_claimed_reward_at = claim_time;
25        self.last_claimed_power = self.current_power;
26    }
27
28    pub fn time_as(&self) -> chrono::TimeDelta {
29        ::sim_clock::utc_now() - self.created_at
30    }
31}
32
33#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
34pub struct Vassal {
35    pub character_id: Uuid,
36    pub username: String,
37    pub photo_url: Option<String>,
38    pub loyalty: i64,
39    pub last_claimed_reward_at: chrono::DateTime<chrono::Utc>,
40    pub last_claimed_power: i64,
41    pub current_power: i64,
42    pub current_reward: Vec<CurrencyUnit>,
43    pub created_at: chrono::DateTime<chrono::Utc>,
44}
45
46impl Vassal {
47    pub fn claim_reward(&mut self, claim_time: chrono::DateTime<chrono::Utc>) {
48        self.current_reward = vec![];
49        self.last_claimed_reward_at = claim_time;
50        self.last_claimed_power = self.current_power;
51    }
52}
53
54#[derive(Default, Serialize, Deserialize)]
55pub struct VassalBuilder {
56    character_id: Uuid,
57    username: String,
58    photo_url: Option<String>,
59    loyalty: i64,
60    last_claimed_reward_at: chrono::DateTime<Utc>,
61    last_claimed_power: i64,
62    current_power: i64,
63    current_reward: Vec<CurrencyUnit>,
64    created_at: chrono::DateTime<Utc>,
65}
66
67impl VassalBuilder {
68    pub fn new() -> Self {
69        Self {
70            character_id: Uuid::now_v7(),
71            username: "".to_owned(),
72            photo_url: None,
73            loyalty: 0,
74            last_claimed_reward_at: ::sim_clock::utc_now(),
75            last_claimed_power: 0,
76            current_power: 0,
77            current_reward: Vec::new(),
78            created_at: ::sim_clock::utc_now(),
79        }
80    }
81
82    pub fn character_id(mut self, character_id: Uuid) -> Self {
83        self.character_id = character_id;
84        self
85    }
86
87    pub fn username(mut self, username: String) -> Self {
88        self.username = username;
89        self
90    }
91
92    pub fn photo_url(mut self, photo_url: Option<String>) -> Self {
93        self.photo_url = photo_url;
94        self
95    }
96
97    pub fn loyalty(mut self, loyalty: i64) -> Self {
98        self.loyalty = loyalty;
99        self
100    }
101
102    pub fn last_claimed_reward_at(mut self, last_claimed_reward_at: chrono::DateTime<Utc>) -> Self {
103        self.last_claimed_reward_at = last_claimed_reward_at;
104        self
105    }
106
107    pub fn last_claimed_power(mut self, last_claimed_power: i64) -> Self {
108        self.last_claimed_power = last_claimed_power;
109        self
110    }
111
112    pub fn current_power(mut self, current_power: i64) -> Self {
113        self.current_power = current_power;
114        self
115    }
116
117    pub fn current_reward(mut self, current_reward: Vec<CurrencyUnit>) -> Self {
118        self.current_reward = current_reward;
119        self
120    }
121
122    pub fn created_at(mut self, created_at: chrono::DateTime<Utc>) -> Self {
123        self.created_at = created_at;
124        self
125    }
126
127    pub fn build(self) -> Vassal {
128        Vassal {
129            character_id: self.character_id,
130            username: self.username,
131            photo_url: self.photo_url,
132            loyalty: self.loyalty,
133            last_claimed_reward_at: self.last_claimed_reward_at,
134            last_claimed_power: self.last_claimed_power,
135            current_power: self.current_power,
136            current_reward: self.current_reward,
137            created_at: self.created_at,
138        }
139    }
140}
141
142#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Copy)]
143pub struct VassalLinkLoyalty {
144    pub suzerain_id: Uuid,
145    pub vassal_id: Uuid,
146    pub loyalty: i64,
147    pub loyalty_set_at: chrono::DateTime<Utc>,
148    pub cur_time: chrono::DateTime<Utc>,
149}
150
151/// Task in config
152#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Tsify, i18n::Translate)]
153pub struct VassalTaskTemplate {
154    #[schemars(schema_with = "id_schema")]
155    pub id: Uuid,
156    #[schemars(title = "Название задания")]
157    #[translate]
158    pub title: i18n::I18nString,
159    #[schemars(title = "Длительность выполнения задания")]
160    pub duration_sec: u64,
161    /// Name of the registered `currencies` native fn computing this task's
162    /// reward (good/bad chosen via the pushed `GoodTask`). Defaults to the
163    /// shipped constant-stub port; config that omits it keeps prod behavior.
164    #[serde(default = "default_vassal_task_reward_fn")]
165    #[schemars(skip)]
166    pub reward_fn: String,
167    /// Name of the registered `expression` native fn computing this task's
168    /// loyalty. Defaults to the shipped constant-stub port.
169    #[serde(default = "default_vassal_task_loyalty_fn")]
170    #[schemars(skip)]
171    pub loyalty_fn: String,
172}
173
174fn default_vassal_task_reward_fn() -> String {
175    "vassal_task_reward_const".to_string()
176}
177
178fn default_vassal_task_loyalty_fn() -> String {
179    "vassal_task_loyalty_const".to_string()
180}
181
182#[derive(
183    Clone,
184    Debug,
185    Serialize,
186    Default,
187    Deserialize,
188    PartialEq,
189    Eq,
190    JsonSchema,
191    Tsify,
192    EnumString,
193    Display,
194)]
195pub enum VassalTaskStatus {
196    #[default]
197    NotStarted,
198    StartedGood,
199    StartedBad,
200    ChangedBadToGood,
201    FinishedGood,
202    FinishedBad,
203}
204
205/// Task in state
206#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
207pub struct VassalTask {
208    pub id: Uuid,
209    pub template_task_id: Uuid,
210    pub suzerain_id: Uuid,
211    pub suzerain_power: i64,
212    pub vassal_id: Uuid,
213    pub vassal_power: i64,
214    pub good_reward: Vec<CurrencyUnit>,
215    pub bad_reward: Vec<CurrencyUnit>,
216    pub good_loyalty: i64,
217    pub bad_loyalty: i64,
218    pub task_status: VassalTaskStatus,
219    pub claimed_by_suzerain: bool,
220    pub claimed_by_vassal: bool,
221    pub started_at: Option<chrono::DateTime<chrono::Utc>>,
222    pub finish_at: Option<chrono::DateTime<chrono::Utc>>,
223}
224
225#[derive(Default, Deserialize, Serialize)]
226pub struct VassalTaskBuilder {
227    pub id: Uuid,
228    pub template_task_id: Uuid,
229    pub suzerain_id: Uuid,
230    pub suzerain_power: i64,
231    pub vassal_id: Uuid,
232    pub vassal_power: i64,
233    pub good_reward: Vec<CurrencyUnit>,
234    pub bad_reward: Vec<CurrencyUnit>,
235    pub good_loyalty: i64,
236    pub bad_loyalty: i64,
237    pub task_status: VassalTaskStatus,
238    pub claimed_by_suzerain: bool,
239    pub claimed_by_vassal: bool,
240    pub started_at: Option<chrono::DateTime<chrono::Utc>>,
241    pub finish_at: Option<chrono::DateTime<chrono::Utc>>,
242}
243
244impl VassalTaskBuilder {
245    pub fn new() -> Self {
246        Self {
247            id: Uuid::now_v7(),
248            template_task_id: Uuid::nil(),
249            suzerain_id: Uuid::now_v7(),
250            // (was a stub 1). Tests build expected tasks from characters with no
251            // items, so the default mirrors the new computed bare power.
252            suzerain_power: 0,
253            vassal_id: Uuid::now_v7(),
254            vassal_power: 0,
255            good_reward: Vec::new(),
256            bad_reward: Vec::new(),
257            good_loyalty: 0,
258            bad_loyalty: 0,
259            task_status: VassalTaskStatus::NotStarted,
260            claimed_by_suzerain: false,
261            claimed_by_vassal: false,
262            started_at: None,
263            finish_at: None,
264        }
265    }
266
267    pub fn id(mut self, id: Uuid) -> Self {
268        self.id = id;
269        self
270    }
271
272    pub fn template_task_id(mut self, template_task_id: Uuid) -> Self {
273        self.template_task_id = template_task_id;
274        self
275    }
276
277    pub fn suzerain_id(mut self, suzerain_id: Uuid) -> Self {
278        self.suzerain_id = suzerain_id;
279        self
280    }
281
282    pub fn suzerain_power(mut self, suzerain_power: i64) -> Self {
283        self.suzerain_power = suzerain_power;
284        self
285    }
286
287    pub fn vassal_id(mut self, vassal_id: Uuid) -> Self {
288        self.vassal_id = vassal_id;
289        self
290    }
291
292    pub fn vassal_power(mut self, vassal_power: i64) -> Self {
293        self.vassal_power = vassal_power;
294        self
295    }
296
297    pub fn good_reward(mut self, good_reward: Vec<CurrencyUnit>) -> Self {
298        self.good_reward = good_reward;
299        self
300    }
301
302    pub fn bad_reward(mut self, bad_reward: Vec<CurrencyUnit>) -> Self {
303        self.bad_reward = bad_reward;
304        self
305    }
306
307    pub fn good_loyalty(mut self, good_loyalty: i64) -> Self {
308        self.good_loyalty = good_loyalty;
309        self
310    }
311
312    pub fn bad_loyalty(mut self, bad_loyalty: i64) -> Self {
313        self.bad_loyalty = bad_loyalty;
314        self
315    }
316
317    pub fn task_status(mut self, task_status: VassalTaskStatus) -> Self {
318        self.task_status = task_status;
319        self
320    }
321
322    pub fn claimed_by_suzerain(mut self, claimed: bool) -> Self {
323        self.claimed_by_suzerain = claimed;
324        self
325    }
326
327    pub fn claimed_by_vassal(mut self, claimed: bool) -> Self {
328        self.claimed_by_vassal = claimed;
329        self
330    }
331
332    pub fn started_at(mut self, started_at: Option<chrono::DateTime<Utc>>) -> Self {
333        self.started_at = started_at;
334        self
335    }
336
337    pub fn finish_at(mut self, finish_at: Option<chrono::DateTime<Utc>>) -> Self {
338        self.finish_at = finish_at;
339        self
340    }
341
342    pub fn build(self) -> VassalTask {
343        VassalTask {
344            id: self.id,
345            template_task_id: self.template_task_id,
346            suzerain_id: self.suzerain_id,
347            suzerain_power: self.suzerain_power,
348            vassal_id: self.vassal_id,
349            vassal_power: self.vassal_power,
350            good_reward: self.good_reward,
351            bad_reward: self.bad_reward,
352            good_loyalty: self.good_loyalty,
353            bad_loyalty: self.bad_loyalty,
354            task_status: self.task_status,
355            claimed_by_suzerain: self.claimed_by_suzerain,
356            claimed_by_vassal: self.claimed_by_vassal,
357            started_at: self.started_at,
358            finish_at: self.finish_at,
359        }
360    }
361}