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(
135 PartialEq, Serialize, Deserialize, Default, Debug, Clone, JsonSchema, Tsify, i18n::Translate,
136)]
137pub struct Class {
138 #[schemars(schema_with = "id_schema")]
139 pub id: ClassId,
140
141 #[schemars(title = "Название класса")]
142 #[translate]
143 pub name: i18n::I18nString,
144
145 #[schemars(title = "Описание класса")]
146 #[translate]
147 pub description: i18n::I18nString,
148
149 #[schemars(title = "Иконка", schema_with = "asset_class_hero_icon")]
150 pub icon_path: String,
151
152 #[schemars(
153 title = "Фон для Hero Screen",
154 schema_with = "asset_class_hero_background"
155 )]
156 pub background_image_path: String,
157
158 #[schemars(title = "Спайн класса", schema_with = "spine_schema")]
159 pub character_asset: String,
160
161 #[schemars(title = "Время каста")]
162 pub cast_time: u64,
163
164 #[schemars(title = "Спайн класса (Unity)", schema_with = "aa_entity_spine_schema")]
165 pub spine: String,
166
167 #[schemars(
168 title = "Базовые способности игрока",
169 description = "Способности, которыми игрок безусловно обладает в бою.",
170 schema_with = "ability_link_id_array_schema"
171 )]
172 pub basic_abilities: Vec<abilities::AbilityId>,
173
174 #[schemars(
175 title = "Активные классовые скиллы",
176 description = "Список активных скиллов класса. Анлокаются и прокачиваются через прокачку класса (ClassLevels.ability_levels), не падают в гаче, экипируются игроком как обычные скиллы. Должны иметь is_gacha_ability=false и не пересекаться с basic_abilities.",
177 schema_with = "ability_link_id_array_schema"
178 )]
179 pub class_abilities: Vec<abilities::AbilityId>,
180
181 #[schemars(
182 title = "Подарочнйый набор новичка",
183 schema_with = "option_bundle_id_schema"
184 )]
185 pub starter_bundle_id: Option<bundles::BundleId>,
186
187 #[schemars(title = "Базовые атрибуты игрока")]
188 pub attributes: Vec<ClassAttribute>,
189
190 #[schemars(
191 title = "Id редкости этого класса",
192 schema_with = "ability_rarity_link_id_schema"
193 )]
194 pub ability_rarity_id: abilities::AbilityRarityId,
195
196 #[schemars(title = "Тир класса")]
197 pub tier: ClassTier,
198
199 #[schemars(
200 title = "Скины для болванки выбора класса",
201 description = "Набор скинов, формирующих внешность \"классического\" представителя класса в экране выбора класса в начале игры",
202 schema_with = "skin_link_id_array_schema"
203 )]
204 pub demo_skins: Vec<SkinId>,
205
206 #[schemars(
207 title = "Тип оружия класса",
208 description = "Отображается в UI; после введения оружейной гачи переедет на enum"
209 )]
210 #[translate]
211 pub weapon_type: i18n::I18nString,
212
213 #[schemars(
214 title = "Пассивка класса",
215 description = "Постоянно действующее правило класса (BAL-033). None — у класса-заглушки."
216 )]
217 pub passive: ClassPassive,
218
219 #[schemars(
220 title = "Множитель Power пассивки на 1 уровне класса",
221 description = "Приблизительный вклад пассивки в displayed Power (BAL-030). 1.0 — не влияет."
222 )]
223 pub passive_power_q_l1: f64,
224
225 #[schemars(
226 title = "Множитель Power пассивки на 20 уровне класса",
227 description = "То же значение на максимальном уровне; промежуточные интерполируются линейно по ln(q)."
228 )]
229 pub passive_power_q_l20: f64,
230
231 #[schemars(
232 title = "Множители Power классовых абилок",
233 description = "По строке на каждую абилку кита; учитывается, только пока абилка экипирована."
234 )]
235 pub ability_power_q: Vec<ClassAbilityPowerQ>,
236
237 #[schemars(
238 title = "Величина пассивки на 1 уровне класса",
239 description = "Проценты: доля MaxHP для лечения, шанс для повтора удара. 0 для None."
240 )]
241 pub passive_percent_l1: f64,
242
243 #[schemars(
244 title = "Величина пассивки на 20 уровне класса",
245 description = "Тот же смысл; уровни между 1 и 20 интерполируются линейно."
246 )]
247 pub passive_percent_l20: f64,
248
249 #[schemars(
250 title = "Период пассивки, тики",
251 description = "Только для периодических пассивок (Priest): через сколько миллисекунд после старта боя и между срабатываниями. 0 у остальных."
252 )]
253 pub passive_period_ticks: u64,
254
255 #[schemars(
256 title = "Основной атрибут класса",
257 description = "Используется в UI блока Class Main Stat",
258 schema_with = "attribute_link_id_schema"
259 )]
260 pub main_attribute: AttributeId,
261
262 #[schemars(
263 title = "Рекомендуемое значение основного атрибута",
264 description = "Отображается в UI как ориентир \"комфортной игры\" на текущий момент"
265 )]
266 pub main_attribute_optimal_value: u64,
267
268 #[schemars(
269 title = "Дефолтный скин оружия класса",
270 description = "Применяется к экипированному оружию после респека, заменяя любой пользовательский скин",
271 schema_with = "skin_link_id_schema"
272 )]
273 pub default_weapon_skin_id: SkinId,
274}