1use essences::{
2 currency::CurrencyId, fighting::FightTemplateId, items::AttributeId, offers::ShopTab,
3};
4use schema_loader::{
5 attribute_link_id_array_schema, attribute_link_id_schema, class_id_schema,
6 currency_link_id_array_schema, currency_link_id_schema, fight_template_link_id_schema,
7 vassal_task_id_schema,
8};
9use schemars::JsonSchema;
10
11use serde::{Deserialize, Serialize};
12use tsify_next::Tsify;
13
14use crate::validated_types::{PositiveI64, WeightMultiplier};
15
16#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
17pub struct GameSettings {
18 #[schemars(
19 title = "Обязательные атрибуты предметов",
20 description = "Атрибуты, которые обязательно будут на предметах их сундука",
21 schema_with = "attribute_link_id_array_schema"
22 )]
23 pub required_attributes: Vec<AttributeId>,
24
25 #[schemars(
26 title = "Id вассальной таски брыкания",
27 schema_with = "vassal_task_id_schema"
28 )]
29 pub resist_task_id: uuid::Uuid,
30
31 #[schemars(title = "Id аттрибута хп", schema_with = "attribute_link_id_schema")]
32 pub hp_attribute_id: uuid::Uuid,
33
34 #[schemars(
35 title = "Id тайм скип билетика",
36 schema_with = "currency_link_id_schema"
37 )]
38 pub time_skip_ticket_currency_id: CurrencyId,
39
40 #[schemars(title = "Сколько секунд апгрейда сундука скипает тайм скип билетик")]
41 pub chest_upgrade_skip_ticket_skips_sec: u64,
42
43 #[schemars(
44 title = "Id валюты для скипа прокачки сундука",
45 schema_with = "currency_link_id_schema"
46 )]
47 pub chest_upgrade_skip_currency_id: CurrencyId,
48
49 #[schemars(title = "Сколько секунд апгрейда сундука скипает одна единица валюты")]
50 pub chest_upgrade_skip_currency_skips_sec: u64,
51
52 #[schemars(title = "Настройки гачи способностей")]
58 pub ability_gacha: AbilityGachaSettings,
59
60 #[schemars(
61 title = "Id валюты для открытия сундука предметов",
62 schema_with = "currency_link_id_schema"
63 )]
64 pub item_case_currency_id: CurrencyId,
65
66 #[schemars(
67 title = "Id изначального класса персонажа",
68 schema_with = "class_id_schema"
69 )]
70 pub initial_class_id: uuid::Uuid,
71
72 #[schemars(title = "Длительность хранения сообщения в часах")]
73 pub chat_message_ttl_secs: u64,
74
75 #[schemars(
76 title = "Базовое значение атрибута speed",
77 description = "Значение атрибута speed на entity, при котором кулдауны идут 1:1 (\"100%\"). При speed выше базового кулдауны идут быстрее, при меньшем — медленнее."
78 )]
79 pub baseline_speed: u64,
80
81 #[schemars(
82 title = "Id валют для отрисовки на главном экране",
83 schema_with = "currency_link_id_array_schema"
84 )]
85 pub currency_ids_to_show: Vec<CurrencyId>,
86
87 #[schemars(title = "Настройки гачи петов")]
88 pub pet_gacha: PetGachaSettings,
89
90 #[schemars(title = "Длительность паузы между открытиями сундука")]
91 pub auto_chest_pause_duration_ticks: u64,
92
93 #[schemars(
94 title = "Id битвы для арены",
95 schema_with = "fight_template_link_id_schema"
96 )]
97 pub arena_fight_template_id: FightTemplateId,
98
99 #[schemars(
100 title = "Id битвы для вассального pvp",
101 schema_with = "fight_template_link_id_schema"
102 )]
103 pub vassal_fight_id: FightTemplateId,
104
105 #[schemars(title = "Как часто срабатывает эвент fight_progress_tick")]
106 pub fight_progress_tick: u64,
107
108 #[schemars(title = "Частота обновления мощи персонажа в базе")]
109 pub db_power_update_frequency: u64,
110
111 #[schemars(title = "Юзернейм подставляющийся игроку удалившему аккаунт")]
112 pub deleted_user_username: String,
113
114 #[schemars(
115 title = "Id валюты бриллиантов",
116 schema_with = "currency_link_id_schema"
117 )]
118 pub diamond_currency_id: CurrencyId,
119
120 #[schemars(title = "Минимальный интервал между сменами username (секунды)")]
121 pub username_change_cooldown_sec: u64,
122
123 #[schemars(title = "Минимальная длина username")]
124 pub username_min_length: usize,
125
126 #[schemars(title = "Максимальная длина username")]
127 pub username_max_length: usize,
128
129 #[schemars(title = "До какого числа обновлять кол-во ключей у пользователя")]
130 pub dungeons_keys_reset_amount: i64,
131
132 #[schemars(title = "Настройки ежедневного ресета валют")]
133 pub daily_currency_resets: Vec<DailyCurrencyReset>,
134
135 #[schemars(title = "Вкладка магазина, открываемая по умолчанию")]
136 pub default_shop_tab: ShopTab,
137
138 #[schemars(
139 title = "Глава, на которой показывается окно \"оцените нас\"",
140 description = "Если задано, сервер эмитит событие ShowRateUs, когда игрок впервые достигает этой главы. None отключает автоматический показ."
141 )]
142 pub rate_us_chapter: Option<i64>,
143
144 #[serde(default)]
145 #[schemars(
146 title = "Рост награды босса за главу",
147 description = "Множитель валюты, выпадающей с босса главы, растёт как boss_reward_chapter_growth^(глава) — глубже глава, больше падает с босса (\"пушить выгодно\"). Масштабируются только боссы (is_boss) в кампанийных боях; треш и не-кампания не затронуты. None или <=1.0 отключает (множитель 1.0)."
148 )]
149 pub boss_reward_chapter_growth: Option<f64>,
150
151 #[serde(default)]
152 #[schemars(
153 title = "Потолок множителя награды босса",
154 description = "Верхняя граница множителя из boss_reward_chapter_growth (защищает экономику/overflow на глубоких главах). None = без доп. потолка (но множитель всё равно ограничен здравым пределом в коде)."
155 )]
156 pub boss_reward_max_multiplier: Option<f64>,
157
158 #[serde(default = "default_default_loop_task_behavior")]
165 #[schemars(skip)]
166 pub default_loop_task_behavior: String,
167}
168
169fn default_default_loop_task_behavior() -> String {
171 "default_loop_task_const".to_string()
172}
173
174#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
175pub struct AbilityGachaSettings {
176 #[schemars(
177 title = "Id валюты для открытия гачи скиллов",
178 schema_with = "currency_link_id_schema"
179 )]
180 pub currency_id: CurrencyId,
181
182 #[schemars(title = "Цена 1 крутки в бриллиантах")]
183 pub roll_price_in_diamonds: PositiveI64,
184
185 #[schemars(title = "Стоимость маленькой крутки")]
188 pub small_roll_cost: PositiveI64,
189
190 #[schemars(title = "Стоимость большой крутки")]
192 pub big_roll_cost: PositiveI64,
193
194 #[schemars(title = "Бонусные дропы в большой крутке")]
196 pub big_roll_bonus_drops: u8,
197
198 #[schemars(title = "Количество слотов вишлиста")]
200 pub wishlist_slots: u8,
201
202 #[schemars(title = "Множитель веса вишлиста")]
205 pub wishlist_weight_multiplier: WeightMultiplier,
206
207 #[schemars(
209 title = "Валюта прокачки слотов способностей",
210 schema_with = "currency_link_id_schema"
211 )]
212 pub slot_upgrade_currency_id: CurrencyId,
213
214 #[schemars(title = "Максимальный уровень слота способности")]
216 pub slot_max_level: PositiveI64,
217
218 #[schemars(title = "Стоимости уровней слотов способностей")]
221 pub slot_level_costs: Vec<PositiveI64>,
222
223 #[schemars(title = "Бонус уровня способности от уровня слота")]
226 pub slot_level_bonus_levels: Vec<i64>,
227}
228
229#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
230pub struct PetGachaSettings {
231 #[schemars(
232 title = "Id валюты для открытия гачи петов",
233 schema_with = "currency_link_id_schema"
234 )]
235 pub currency_id: CurrencyId,
236
237 #[schemars(title = "Цена 1 крутки в бриллиантах")]
238 pub roll_price_in_diamonds: PositiveI64,
239
240 #[schemars(title = "Стоимость маленькой крутки")]
243 pub small_roll_cost: PositiveI64,
244
245 #[schemars(title = "Стоимость большой крутки")]
247 pub big_roll_cost: PositiveI64,
248
249 #[schemars(title = "Бонусные дропы в большой крутке")]
251 pub big_roll_bonus_drops: u8,
252
253 #[schemars(title = "Количество слотов вишлиста")]
255 pub wishlist_slots: u8,
256
257 #[schemars(title = "Множитель веса вишлиста")]
260 pub wishlist_weight_multiplier: WeightMultiplier,
261}
262
263#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
264pub struct DailyCurrencyReset {
265 #[schemars(
266 title = "ID валюты для ресета",
267 schema_with = "currency_link_id_schema"
268 )]
269 pub currency_id: CurrencyId,
270
271 #[schemars(title = "Значение, до которого ресетить валюту")]
272 pub reset_amount: i64,
273}
274
275impl GameSettings {
276 pub fn get_daily_currency_reset_amount(&self, currency_id: CurrencyId) -> anyhow::Result<i64> {
277 self.daily_currency_resets
278 .iter()
279 .find(|reset| reset.currency_id == currency_id)
280 .map(|reset| reset.reset_amount)
281 .ok_or_else(|| {
282 anyhow::anyhow!(
283 "Currency {} not found in daily_currency_resets",
284 currency_id
285 )
286 })
287 }
288}