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        ::time::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: ::time::utc_now(),
75            last_claimed_power: 0,
76            current_power: 0,
77            current_reward: Vec::new(),
78            created_at: ::time::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)]
153pub struct VassalTaskTemplate {
154    #[schemars(schema_with = "id_schema")]
155    pub id: Uuid,
156    #[schemars(title = "Название задания")]
157    pub title: i18n::I18nString,
158    #[schemars(title = "Длительность выполнения задания")]
159    pub duration_sec: u64,
160    /// Name of the registered `currencies` native fn computing this task's
161    /// reward (good/bad chosen via the pushed `GoodTask`). Defaults to the
162    /// shipped constant-stub port; config that omits it keeps prod behavior.
163    #[serde(default = "default_vassal_task_reward_fn")]
164    #[schemars(skip)]
165    pub reward_fn: String,
166    /// Name of the registered `expression` native fn computing this task's
167    /// loyalty. Defaults to the shipped constant-stub port.
168    #[serde(default = "default_vassal_task_loyalty_fn")]
169    #[schemars(skip)]
170    pub loyalty_fn: String,
171}
172
173fn default_vassal_task_reward_fn() -> String {
174    "vassal_task_reward_const".to_string()
175}
176
177fn default_vassal_task_loyalty_fn() -> String {
178    "vassal_task_loyalty_const".to_string()
179}
180
181#[derive(
182    Clone,
183    Debug,
184    Serialize,
185    Default,
186    Deserialize,
187    PartialEq,
188    Eq,
189    JsonSchema,
190    Tsify,
191    EnumString,
192    Display,
193)]
194pub enum VassalTaskStatus {
195    #[default]
196    NotStarted,
197    StartedGood,
198    StartedBad,
199    ChangedBadToGood,
200    FinishedGood,
201    FinishedBad,
202}
203
204/// Task in state
205#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
206pub struct VassalTask {
207    pub id: Uuid,
208    pub template_task_id: Uuid,
209    pub suzerain_id: Uuid,
210    pub suzerain_power: i64,
211    pub vassal_id: Uuid,
212    pub vassal_power: i64,
213    pub good_reward: Vec<CurrencyUnit>,
214    pub bad_reward: Vec<CurrencyUnit>,
215    pub good_loyalty: i64,
216    pub bad_loyalty: i64,
217    pub task_status: VassalTaskStatus,
218    pub claimed_by_suzerain: bool,
219    pub claimed_by_vassal: bool,
220    pub started_at: Option<chrono::DateTime<chrono::Utc>>,
221    pub finish_at: Option<chrono::DateTime<chrono::Utc>>,
222}
223
224#[derive(Default, Deserialize, Serialize)]
225pub struct VassalTaskBuilder {
226    pub id: Uuid,
227    pub template_task_id: Uuid,
228    pub suzerain_id: Uuid,
229    pub suzerain_power: i64,
230    pub vassal_id: Uuid,
231    pub vassal_power: i64,
232    pub good_reward: Vec<CurrencyUnit>,
233    pub bad_reward: Vec<CurrencyUnit>,
234    pub good_loyalty: i64,
235    pub bad_loyalty: i64,
236    pub task_status: VassalTaskStatus,
237    pub claimed_by_suzerain: bool,
238    pub claimed_by_vassal: bool,
239    pub started_at: Option<chrono::DateTime<chrono::Utc>>,
240    pub finish_at: Option<chrono::DateTime<chrono::Utc>>,
241}
242
243impl VassalTaskBuilder {
244    pub fn new() -> Self {
245        Self {
246            id: Uuid::now_v7(),
247            template_task_id: Uuid::nil(),
248            suzerain_id: Uuid::now_v7(),
249            // (was a stub 1). Tests build expected tasks from characters with no
250            // items, so the default mirrors the new computed bare power.
251            suzerain_power: 0,
252            vassal_id: Uuid::now_v7(),
253            vassal_power: 0,
254            good_reward: Vec::new(),
255            bad_reward: Vec::new(),
256            good_loyalty: 0,
257            bad_loyalty: 0,
258            task_status: VassalTaskStatus::NotStarted,
259            claimed_by_suzerain: false,
260            claimed_by_vassal: false,
261            started_at: None,
262            finish_at: None,
263        }
264    }
265
266    pub fn id(mut self, id: Uuid) -> Self {
267        self.id = id;
268        self
269    }
270
271    pub fn template_task_id(mut self, template_task_id: Uuid) -> Self {
272        self.template_task_id = template_task_id;
273        self
274    }
275
276    pub fn suzerain_id(mut self, suzerain_id: Uuid) -> Self {
277        self.suzerain_id = suzerain_id;
278        self
279    }
280
281    pub fn suzerain_power(mut self, suzerain_power: i64) -> Self {
282        self.suzerain_power = suzerain_power;
283        self
284    }
285
286    pub fn vassal_id(mut self, vassal_id: Uuid) -> Self {
287        self.vassal_id = vassal_id;
288        self
289    }
290
291    pub fn vassal_power(mut self, vassal_power: i64) -> Self {
292        self.vassal_power = vassal_power;
293        self
294    }
295
296    pub fn good_reward(mut self, good_reward: Vec<CurrencyUnit>) -> Self {
297        self.good_reward = good_reward;
298        self
299    }
300
301    pub fn bad_reward(mut self, bad_reward: Vec<CurrencyUnit>) -> Self {
302        self.bad_reward = bad_reward;
303        self
304    }
305
306    pub fn good_loyalty(mut self, good_loyalty: i64) -> Self {
307        self.good_loyalty = good_loyalty;
308        self
309    }
310
311    pub fn bad_loyalty(mut self, bad_loyalty: i64) -> Self {
312        self.bad_loyalty = bad_loyalty;
313        self
314    }
315
316    pub fn task_status(mut self, task_status: VassalTaskStatus) -> Self {
317        self.task_status = task_status;
318        self
319    }
320
321    pub fn claimed_by_suzerain(mut self, claimed: bool) -> Self {
322        self.claimed_by_suzerain = claimed;
323        self
324    }
325
326    pub fn claimed_by_vassal(mut self, claimed: bool) -> Self {
327        self.claimed_by_vassal = claimed;
328        self
329    }
330
331    pub fn started_at(mut self, started_at: Option<chrono::DateTime<Utc>>) -> Self {
332        self.started_at = started_at;
333        self
334    }
335
336    pub fn finish_at(mut self, finish_at: Option<chrono::DateTime<Utc>>) -> Self {
337        self.finish_at = finish_at;
338        self
339    }
340
341    pub fn build(self) -> VassalTask {
342        VassalTask {
343            id: self.id,
344            template_task_id: self.template_task_id,
345            suzerain_id: self.suzerain_id,
346            suzerain_power: self.suzerain_power,
347            vassal_id: self.vassal_id,
348            vassal_power: self.vassal_power,
349            good_reward: self.good_reward,
350            bad_reward: self.bad_reward,
351            good_loyalty: self.good_loyalty,
352            bad_loyalty: self.bad_loyalty,
353            task_status: self.task_status,
354            claimed_by_suzerain: self.claimed_by_suzerain,
355            claimed_by_vassal: self.claimed_by_vassal,
356            started_at: self.started_at,
357            finish_at: self.finish_at,
358        }
359    }
360}