essences/
item_case.rs

1use crate::items::ItemRarityId;
2use crate::prelude::*;
3use crate::{
4    currency::CurrencyUnit,
5    flip::WorldSide,
6    items::{EquipmentSlotKey, ItemType},
7};
8
9#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
10pub struct ItemCaseRarityWeight {
11    #[schemars(schema_with = "item_rarity_link_id_schema")]
12    pub rarity_id: ItemRarityId,
13
14    #[schemars(title = "Вес редкости")]
15    pub weight: f64,
16}
17
18// Две РАЗНЫЕ лестницы, по одной на каждое событие открытия сундука:
19//   max_batch_size           -> OpenItemCase (ручное открытие)
20//   auto_only_max_batch_size -> AutoChestOpenItemCase (авто-режим)
21// До разделения оба пути читали общий max_batch_size, поэтому не переносите
22// значения между полями. Инварианты (обе лестницы не убывают с уровнем сундука,
23// авто никогда не превышает ручную) проверяются в
24// `GameConfig::validate_item_cases_settings`.
25//
26// Ручная лестница — не настройка в интерфейсе: главный экран сундука шлёт ровно
27// 1 за нажатие, доска Plinko склеивает нажатия, накопленные за один обмен с
28// сервером. Её верхние значения работают как ограничение на пришедшее от
29// клиента число итераций (см. проверку в `logic::items::open_item_case`).
30// Игровая пропускная способность настраивается авто-лестницей.
31#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
32pub struct AutoChestSettings {
33    #[schemars(
34        title = "Максимальный размер батча при ручном открытии",
35        description = "Сколько сундуков игрок может открыть за одно РУЧНОЕ нажатие. Авто-открытие ограничивается отдельным auto_only_max_batch_size."
36    )]
37    pub max_batch_size: i64,
38
39    #[schemars(
40        title = "Максимальный размер батча в авточесте",
41        description = "Сколько сундуков открывает АВТО-режим за один батч. Отдельная, более низкая лестница: авто идёт непрерывно, поэтому его пропускная способность ограничивается жёстче ручной. Пропускная способность = 3600 × batch / (2 + 0.35 × batch) открытий в час."
42    )]
43    pub auto_only_max_batch_size: i64,
44}
45
46#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
47pub struct ItemCasesSettingsByLevel {
48    #[schemars(title = "Уровень сундука")]
49    pub level: i64,
50
51    #[schemars(title = "Требуемый уровень главы для апгрейда")]
52    pub required_chapter_level: i64,
53
54    #[schemars(title = "Стоимость уровня")]
55    pub upgrade_cost: Vec<CurrencyUnit>,
56
57    #[schemars(title = "Длительность прокачки сундука до следующего уровня (сек.)")]
58    pub upgrade_time_secs: u64,
59
60    #[schemars(title = "Веса редкостей")]
61    pub rarity_weights: Vec<ItemCaseRarityWeight>,
62
63    #[schemars(title = "Настройки авточеста")]
64    pub auto_chest_settings: AutoChestSettings,
65}
66
67#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema, Tsify)]
68pub struct InventorySlotConfig {
69    #[schemars(title = "Тип предмета")]
70    pub item_type: ItemType,
71    #[schemars(
72        title = "Сторона мира",
73        description = "Обязательна для flip-слотов и отсутствует у постоянных слотов."
74    )]
75    pub world_side: Option<WorldSide>,
76}
77
78impl InventorySlotConfig {
79    pub const fn equipment_slot_key(&self) -> EquipmentSlotKey {
80        EquipmentSlotKey::new(self.item_type, self.world_side)
81    }
82}
83
84#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Tsify)]
85pub struct InventoryLevel {
86    #[schemars(title = "Минимальный уровень главы")]
87    pub from_chapter_level: i64,
88    #[schemars(
89        title = "Доступные с уровня логические слоты",
90        description = "У flip-предметов Real и Fantasy открываются независимо."
91    )]
92    pub slots: Vec<InventorySlotConfig>,
93}