1use super::{abilities, bundles, currency::CurrencyUnit, game};
2use crate::characters::CharacterId;
3use crate::items::AttributeId;
4use crate::skins::SkinId;
5
6use crate::prelude::*;
7
8#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
9pub struct CharacterClass {
10 pub character_id: CharacterId,
11 pub class_id: ClassId,
12 pub level: u64,
13 pub xp: u64,
14}
15
16#[derive(PartialEq, Serialize, Deserialize, Default, Debug, Clone, JsonSchema, Tsify)]
21pub struct ClassAbilityPowerQ {
22 #[schemars(title = "Id абилки", schema_with = "ability_link_id_schema")]
23 pub ability_id: abilities::AbilityId,
24
25 #[schemars(
26 title = "Множитель Power",
27 description = "1.0 — утилита абилки уже полностью учтена в статах."
28 )]
29 pub q: f64,
30}
31
32#[derive(PartialEq, Eq, Serialize, Deserialize, Default, Debug, Clone, JsonSchema, Tsify)]
33pub struct ClassAbilityLevel {
34 #[schemars(title = "Id абилки", schema_with = "ability_link_id_schema")]
35 pub ability_id: abilities::AbilityId,
36 #[schemars(title = "Уровень абилки, до которого она прокачивается на этом уровне класса")]
37 pub level: u64,
38}
39
40#[derive(PartialEq, Eq, Serialize, Deserialize, Default, Debug, Clone, JsonSchema, Tsify)]
41pub struct ClassLevels {
42 #[schemars(schema_with = "class_id_schema")]
43 pub class_id: ClassId,
44
45 #[schemars(title = "Уровень класса")]
46 pub level: u64,
47
48 #[schemars(
49 title = "Атрибуты, выдаваемые на этом уровне",
50 description = "Список бонусов к атрибутам, которые игрок получает с этого уровня класса"
51 )]
52 pub attrs: Vec<game::EntityAttribute>,
53
54 #[schemars(
55 title = "Стоимость прокачки",
56 description = "Цена в валюте за прокачку с предыдущего уровня"
57 )]
58 pub price: CurrencyUnit,
59
60 #[schemars(
61 title = "Анлоки/прокачки классовых абилок",
62 description = "Список пар (абилка, уровень), применяемых на этом уровне класса"
63 )]
64 pub ability_levels: Vec<ClassAbilityLevel>,
65}
66use strum_macros::{Display, EnumIter, EnumString};
67
68#[derive(
69 Debug,
70 Clone,
71 Copy,
72 EnumString,
73 Display,
74 Deserialize,
75 Serialize,
76 Hash,
77 Eq,
78 PartialEq,
79 EnumIter,
80 Default,
81 JsonSchema,
82 Tsify,
83)]
84#[tsify(namespace)]
85pub enum ClassTier {
86 #[default]
87 S,
88 A,
89 B,
90 C,
91}
92
93#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, Eq, PartialEq, JsonSchema, Tsify)]
101#[tsify(namespace)]
102pub enum ClassPassive {
103 #[default]
105 None,
106 BlockHeal,
108 DoubleStrike,
110 Multicast,
113 LowestAllyHeal,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, JsonSchema)]
119pub enum ClassAttribute {
120 EntityAttribute(game::EntityAttribute),
121}
122
123#[declare]
124pub type ClassId = Uuid;
125
126impl ClassPassive {
127 pub const fn is_periodic(self) -> bool {
129 matches!(self, Self::LowestAllyHeal)
130 }
131}
132
133#[derive(PartialEq, Serialize, Deserialize, Default, Debug, Clone, JsonSchema, Tsify)]
135pub struct Class {
136 #[schemars(schema_with = "id_schema")]
137 pub id: ClassId,
138
139 #[schemars(title = "Название класса")]
140 pub name: i18n::I18nString,
141
142 #[schemars(title = "Описание класса")]
143 pub description: i18n::I18nString,
144
145 #[schemars(title = "Иконка", schema_with = "asset_class_hero_icon")]
146 pub icon_path: String,
147
148 #[schemars(
149 title = "Фон для Hero Screen",
150 schema_with = "asset_class_hero_background"
151 )]
152 pub background_image_path: String,
153
154 #[schemars(title = "Спайн класса", schema_with = "spine_schema")]
155 pub character_asset: String,
156
157 #[schemars(title = "Время каста")]
158 pub cast_time: u64,
159
160 #[schemars(title = "Спайн класса (Unity)", schema_with = "aa_entity_spine_schema")]
161 pub spine: String,
162
163 #[schemars(
164 title = "Базовые способности игрока",
165 description = "Способности, которыми игрок безусловно обладает в бою.",
166 schema_with = "ability_link_id_array_schema"
167 )]
168 pub basic_abilities: Vec<abilities::AbilityId>,
169
170 #[schemars(
171 title = "Активные классовые скиллы",
172 description = "Список активных скиллов класса. Анлокаются и прокачиваются через прокачку класса (ClassLevels.ability_levels), не падают в гаче, экипируются игроком как обычные скиллы. Должны иметь is_gacha_ability=false и не пересекаться с basic_abilities.",
173 schema_with = "ability_link_id_array_schema"
174 )]
175 pub class_abilities: Vec<abilities::AbilityId>,
176
177 #[schemars(
178 title = "Подарочнйый набор новичка",
179 schema_with = "option_bundle_id_schema"
180 )]
181 pub starter_bundle_id: Option<bundles::BundleId>,
182
183 #[schemars(title = "Базовые атрибуты игрока")]
184 pub attributes: Vec<ClassAttribute>,
185
186 #[schemars(
187 title = "Id редкости этого класса",
188 schema_with = "ability_rarity_link_id_schema"
189 )]
190 pub ability_rarity_id: abilities::AbilityRarityId,
191
192 #[schemars(title = "Тир класса")]
193 pub tier: ClassTier,
194
195 #[schemars(
196 title = "Скины для болванки выбора класса",
197 description = "Набор скинов, формирующих внешность \"классического\" представителя класса в экране выбора класса в начале игры",
198 schema_with = "skin_link_id_array_schema"
199 )]
200 pub demo_skins: Vec<SkinId>,
201
202 #[schemars(
203 title = "Тип оружия класса",
204 description = "Отображается в UI; после введения оружейной гачи переедет на enum"
205 )]
206 pub weapon_type: i18n::I18nString,
207
208 #[schemars(
209 title = "Пассивка класса",
210 description = "Постоянно действующее правило класса (BAL-033). None — у класса-заглушки."
211 )]
212 pub passive: ClassPassive,
213
214 #[schemars(
215 title = "Множитель Power пассивки на 1 уровне класса",
216 description = "Приблизительный вклад пассивки в displayed Power (BAL-030). 1.0 — не влияет."
217 )]
218 pub passive_power_q_l1: f64,
219
220 #[schemars(
221 title = "Множитель Power пассивки на 20 уровне класса",
222 description = "То же значение на максимальном уровне; промежуточные интерполируются линейно по ln(q)."
223 )]
224 pub passive_power_q_l20: f64,
225
226 #[schemars(
227 title = "Множители Power классовых абилок",
228 description = "По строке на каждую абилку кита; учитывается, только пока абилка экипирована."
229 )]
230 pub ability_power_q: Vec<ClassAbilityPowerQ>,
231
232 #[schemars(
233 title = "Величина пассивки на 1 уровне класса",
234 description = "Проценты: доля MaxHP для лечения, шанс для повтора удара. 0 для None."
235 )]
236 pub passive_percent_l1: f64,
237
238 #[schemars(
239 title = "Величина пассивки на 20 уровне класса",
240 description = "Тот же смысл; уровни между 1 и 20 интерполируются линейно."
241 )]
242 pub passive_percent_l20: f64,
243
244 #[schemars(
245 title = "Период пассивки, тики",
246 description = "Только для периодических пассивок (Priest): через сколько миллисекунд после старта боя и между срабатываниями. 0 у остальных."
247 )]
248 pub passive_period_ticks: u64,
249
250 #[schemars(
251 title = "Основной атрибут класса",
252 description = "Используется в UI блока Class Main Stat",
253 schema_with = "attribute_link_id_schema"
254 )]
255 pub main_attribute: AttributeId,
256
257 #[schemars(
258 title = "Рекомендуемое значение основного атрибута",
259 description = "Отображается в UI как ориентир \"комфортной игры\" на текущий момент"
260 )]
261 pub main_attribute_optimal_value: u64,
262
263 #[schemars(
264 title = "Дефолтный скин оружия класса",
265 description = "Применяется к экипированному оружию после респека, заменяя любой пользовательский скин",
266 schema_with = "skin_link_id_schema"
267 )]
268 pub default_weapon_skin_id: SkinId,
269}