1use crate::prelude::*;
2use event_system::script::types::ESCurrencyUnit;
3
4#[declare]
5pub type CurrencyId = uuid::Uuid;
6
7#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
28#[tsify(from_wasm_abi, into_wasm_abi)]
29pub enum CurrencySource {
30 EntityDeath,
31 ItemSell,
32 AutoItemSell,
33 QuestClaim,
34 QuestsTrackReward,
35 VassalTaskCompletion,
36 ReferralLvlUp,
37 ReferralDailyReward,
38 GiftClaim,
39 ArenaTicketBuy,
40 ClaimVassalReward,
41 ClaimSuzerainReward,
42 ArenaMatchmakingRefresh,
43 GachaLevelUp,
44 PetCaseLevelUp,
45 #[default]
49 BundleClaim,
50 AdReward,
51 ProgressPassClaim,
52 Cheat,
53 MailReward,
57 DungeonReward,
58 OfferBuy,
59 ChapterReward,
60 NewUserGrant,
61 PvpArenaReward,
62 PvpVassalReward,
63 AfkReward,
64 DailyReset,
65 RatingReward,
66 CoreReset,
67}
68
69impl serde::Serialize for CurrencySource {
70 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71 where
72 S: serde::Serializer,
73 {
74 let (idx, name) = match self {
84 Self::EntityDeath => (0u32, "EntityDeath"),
85 Self::ItemSell => (1, "ItemSell"),
86 Self::AutoItemSell => (2, "AutoItemSell"),
87 Self::QuestClaim => (3, "QuestClaim"),
88 Self::QuestsTrackReward => (4, "QuestsTrackReward"),
89 Self::VassalTaskCompletion => (5, "VassalTaskCompletion"),
90 Self::ReferralLvlUp => (6, "ReferralLvlUp"),
91 Self::ReferralDailyReward => (7, "ReferralDailyReward"),
92 Self::GiftClaim => (8, "GiftClaim"),
93 Self::ArenaTicketBuy => (9, "ArenaTicketBuy"),
94 Self::ClaimVassalReward => (10, "ClaimVassalReward"),
95 Self::ClaimSuzerainReward => (11, "ClaimSuzerainReward"),
96 Self::ArenaMatchmakingRefresh => (12, "ArenaMatchmakingRefresh"),
97 Self::GachaLevelUp => (13, "GachaLevelUp"),
98 Self::PetCaseLevelUp => (14, "PetCaseLevelUp"),
99 Self::BundleClaim => (15, "BundleClaim"),
100 Self::AdReward => (16, "AdReward"),
101 Self::Cheat => (18, "Cheat"),
104 Self::MailReward
106 | Self::DungeonReward
107 | Self::OfferBuy
108 | Self::ChapterReward
109 | Self::NewUserGrant
110 | Self::PvpArenaReward
111 | Self::PvpVassalReward
112 | Self::AfkReward
113 | Self::DailyReset
114 | Self::RatingReward
115 | Self::CoreReset
116 | Self::ProgressPassClaim => (15, "BundleClaim"),
117 };
118 serializer.serialize_unit_variant("CurrencySource", idx, name)
119 }
120}
121
122#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
123#[tsify(from_wasm_abi, into_wasm_abi)]
124pub enum CurrencyConsumer {
125 AbilityCaseOpen,
126 AbilityCaseSlotUpgrade,
127 ItemCaseOpen,
128 GiftSend,
129 DungeonRaid,
130 DungeonFightEnd,
131 ClassLevelUp,
132 OfferBuy,
133 ItemCaseUpgrade,
134 CaseUpgradeSpeedUp,
135 CaseUpgradeSkip,
136 ArenaFight,
137 ArenaMatchmakingRefresh,
138 ArenaTicketBuy,
139 SkinBuy,
140 AfkInstantReward,
141 StatueRoll,
142 TalentUpgrade,
143 TalentUpgradeSkip,
144 PetCaseOpen,
145 CoreUpgrade,
147}
148
149#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
150pub struct Currency {
151 #[schemars(schema_with = "id_schema")]
152 pub id: CurrencyId,
153 #[schemars(title = "Название")]
154 pub name: i18n::I18nString,
155 #[schemars(title = "Описание")]
156 pub description: i18n::I18nString,
157 #[schemars(title = "URL картинки", schema_with = "webp_url_schema")]
158 pub icon_url: String,
159 #[schemars(title = "Иконка", schema_with = "asset_currency_icon_schema")]
160 pub icon_path: String,
161}
162
163#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, JsonSchema, Tsify, Default)]
164pub struct CurrencyUnit {
165 #[schemars(schema_with = "currency_link_id_schema")]
166 pub currency_id: CurrencyId,
167 #[schemars(title = "Количество")]
168 pub amount: i64,
169}
170
171impl PartialOrd for CurrencyUnit {
172 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
173 Some(self.cmp(other))
174 }
175}
176
177impl Ord for CurrencyUnit {
178 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
179 match self.currency_id.cmp(&other.currency_id) {
180 std::cmp::Ordering::Equal => self.amount.cmp(&other.amount),
181 ordering => ordering,
182 }
183 }
184}
185
186pub fn increase_currencies(
187 currencies_to_increase: &mut Vec<CurrencyUnit>,
188 currencies_to_add: &[CurrencyUnit],
189) {
190 for add_currency in currencies_to_add {
191 if let Some(unit) = currencies_to_increase
192 .iter_mut()
193 .find(|unit| unit.currency_id == add_currency.currency_id)
194 {
195 unit.amount += add_currency.amount;
196 } else {
197 currencies_to_increase.push(add_currency.clone());
198 }
199 }
200}
201
202pub fn decrease_currencies(
203 currencies_to_decrease: &mut [CurrencyUnit],
204 currencies_to_subtract: &[CurrencyUnit],
205) -> anyhow::Result<()> {
206 for subtract_currency in currencies_to_subtract {
207 if let Some(unit) = currencies_to_decrease
208 .iter_mut()
209 .find(|unit| unit.currency_id == subtract_currency.currency_id)
210 {
211 if unit.amount < subtract_currency.amount {
212 anyhow::bail!(
213 "Required currency {subtract_currency:?} is bigger than available {unit:?}"
214 )
215 }
216
217 unit.amount -= subtract_currency.amount;
218 } else {
219 anyhow::bail!("Given currency {subtract_currency:?} isn't present in currencies")
220 }
221 }
222 Ok(())
223}
224
225pub fn force_decrease_currencies(
226 currencies_to_decrease: &mut Vec<CurrencyUnit>,
227 currencies_to_subtract: &[CurrencyUnit],
228) -> anyhow::Result<()> {
229 for subtract_currency in currencies_to_subtract {
230 if let Some(unit) = currencies_to_decrease
231 .iter_mut()
232 .find(|unit| unit.currency_id == subtract_currency.currency_id)
233 {
234 unit.amount -= subtract_currency.amount;
235 }
236 }
237
238 currencies_to_decrease.retain(|unit| unit.amount != 0);
239
240 Ok(())
241}
242
243pub fn check_can_decrease_currencies(
244 available_currencies: &[CurrencyUnit],
245 required_currencies: &[CurrencyUnit],
246) -> bool {
247 for subtract_currency in required_currencies {
248 if let Some(unit) = available_currencies
249 .iter()
250 .find(|unit| unit.currency_id == subtract_currency.currency_id)
251 {
252 if unit.amount < subtract_currency.amount {
253 return false;
254 }
255 } else {
256 return false;
257 }
258 }
259 true
260}
261
262pub fn from_es_currencies(es_currencies: &[ESCurrencyUnit]) -> Vec<CurrencyUnit> {
263 let mut result = vec![];
264 for es_currency in es_currencies.iter() {
265 result.push(CurrencyUnit {
266 currency_id: es_currency.currency_id,
267 amount: es_currency.amount,
268 });
269 }
270 result
271}