configs/
fighting.rs

1use essences::{
2    bundles::BundleId,
3    currency::{CurrencyId, CurrencyUnit},
4    entity::Coordinates,
5};
6
7use schema_loader::{bundle_id_schema, currency_link_id_schema, id_schema};
8use schemars::JsonSchema;
9
10use serde::{Deserialize, Serialize};
11use tsify_next::Tsify;
12
13#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
14pub struct FightSettings {
15    #[schemars(
16        title = "Время ожидания перед стартом следующего боя в тиках",
17        description = "Это момент анимации перебежки персонажа между битвами"
18    )]
19    pub start_fight_delay_ticks_default: u64,
20
21    #[schemars(
22        title = "Время ожидания перед стартом уже начавшегося боя в случае победы",
23        description = "Это момент, когда враги выбегают на экран"
24    )]
25    pub prepare_fight_win_delay_ticks_default: u64,
26
27    #[schemars(
28        title = "Время ожидания перед стартом уже начавшегося боя в случае поражения",
29        description = "Это момент, когда враги выбегают на экран"
30    )]
31    pub prepare_fight_lose_delay_ticks_default: u64,
32
33    #[schemars(title = "Время ожидания перед окончанием боя")]
34    pub end_fight_delay_ticks_default: u64,
35
36    #[schemars(title = "Стартовые координаты игрока")]
37    pub player_start_position: Coordinates,
38
39    #[schemars(title = "Стартовые координаты союзника по пати")]
40    pub party_start_position: Coordinates,
41
42    #[schemars(title = "Стартовые координаты врага в pvp")]
43    pub pvp_enemy_start_position: Coordinates,
44
45    /// Ally-team run speed multiplier (docs/combat-feel-porting-plan.md [3.4]): scales the
46    /// hero's/allies' runs — the between-wave advance dash and in-fight repositioning. Kept
47    /// separate from the `speed` attribute on purpose: `speed` also scales ability cooldowns
48    /// (`scale_cooldown_for_speed`), so it can't be used to speed movement up alone.
49    #[schemars(
50        title = "Множитель скорости бега союзников",
51        description = "Ускоряет перебежку между волнами и подбегания героя/союзников. 1 = как раньше, 2 = вдвое быстрее. На кулдауны не влияет."
52    )]
53    pub ally_run_speed_mult: f64,
54
55    /// Wave-entrance knobs (docs/combat-grid-migration-plan.md, фаза 1): the former
56    /// WAVE_ENTRANCE_* Rust constants become config so the entrance feel is tunable
57    /// without a rebuild. Defaults reproduce the old constants bit-for-bit.
58    #[serde(default = "default_wave_entrance_offset_cells")]
59    #[schemars(
60        title = "Вход волны: офсет спавна (клетки)",
61        description = "На сколько клеток за боевым слотом (за экраном) спавнится моб перед входом."
62    )]
63    pub wave_entrance_offset_cells: i64,
64
65    #[serde(default = "default_wave_entrance_rush_ms_per_cell")]
66    #[schemars(
67        title = "Вход волны: раш-темп (мс/клетка)",
68        description = "Темп входа открывающей группы волны (юниты с минимальным delay)."
69    )]
70    pub wave_entrance_rush_ms_per_cell: u64,
71
72    #[serde(default = "default_wave_entrance_walk_ms_per_cell")]
73    #[schemars(
74        title = "Вход волны: шаг-темп (мс/клетка)",
75        description = "Темп входа остальных эшелонов волны и релизов стрим-пула."
76    )]
77    pub wave_entrance_walk_ms_per_cell: u64,
78
79    /// Slot-model formation dash (docs/combat-grid-migration-plan.md §2.7): fixed
80    /// duration of the hero+formation between-wave run. Read by the slot-model
81    /// server from фаза 2; until then the value is inert data.
82    #[serde(default = "default_formation_advance_ticks")]
83    #[schemars(
84        title = "Слоты: длительность межволновой пробежки (тики = мс)",
85        description = "Пробежка героя и формации к новой позиции после зачистки волны. 1150 = 1.15 с (лабовый advanceRunSeconds). До перехода сервера на слотовую модель не используется."
86    )]
87    pub formation_advance_ticks: u64,
88}
89
90fn default_wave_entrance_offset_cells() -> i64 {
91    4
92}
93
94fn default_wave_entrance_rush_ms_per_cell() -> u64 {
95    200
96}
97
98fn default_wave_entrance_walk_ms_per_cell() -> u64 {
99    500
100}
101
102fn default_formation_advance_ticks() -> u64 {
103    1150
104}
105
106#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, Tsify)]
107pub struct PvpSettings {
108    #[schemars(
109        title = "Максимальное количество оппонентов",
110        description = "Максимальное количество оппонентов для отображения на экране подбора игроков"
111    )]
112    pub max_matchmaking_opponents_count: i64,
113
114    #[schemars(title = "Дельта уровня пользователя для матчмейкинга")]
115    pub matchmaking_character_level_data: i64,
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Tsify)]
119pub struct ArenaLeague {
120    #[schemars(schema_with = "id_schema")]
121    pub id: uuid::Uuid,
122
123    #[schemars(title = "Название лиги")]
124    pub name: i18n::I18nString,
125
126    #[schemars(title = "Минимальный рейтинг")]
127    pub min_rating: i64,
128
129    #[schemars(title = "Максимальный рейтинг")]
130    pub max_rating: i64,
131}
132
133#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Tsify)]
134pub struct ArenaSettings {
135    #[schemars(title = "Базовый рейтинг пользователя")]
136    pub base_rating: u64,
137
138    #[schemars(title = "Количество последних матчей на экране истории")]
139    pub matches_history_size: u64,
140
141    #[schemars(title = "Размер таблицы лидеров")]
142    pub leaderboard_size: u64,
143
144    #[schemars(
145        title = "Идентификатор валюты pvp токенов",
146        schema_with = "currency_link_id_schema"
147    )]
148    pub arena_tickets_currency_id: CurrencyId,
149
150    #[schemars(title = "Максимальная разница между рейтингами игроков для подбора")]
151    pub matchmaking_character_rating_delta: u64,
152
153    #[schemars(title = "Кулдаун pvp")]
154    pub pvp_cooldown_secs: u64,
155
156    #[schemars(
157        title = "ID бандла награды за победу в арене",
158        schema_with = "bundle_id_schema"
159    )]
160    pub win_reward_bundle_id: BundleId,
161
162    #[schemars(
163        title = "ID бандла награды за поражение в арене",
164        schema_with = "bundle_id_schema"
165    )]
166    pub lose_reward_bundle_id: BundleId,
167
168    #[schemars(
169        title = "Валюта для покупки аренных билетов",
170        schema_with = "currency_link_id_schema"
171    )]
172    pub arena_ticket_buy_currency_id: CurrencyId,
173
174    #[schemars(title = "Стоимость покупки аренных билетов")]
175    pub arena_ticket_price: CurrencyUnit,
176
177    #[schemars(title = "Количество дней жизни матчей в базе данных")]
178    pub arena_matches_ttl_days: u64,
179
180    #[schemars(title = "Максимальное увеличение рейтинга в рематче")]
181    pub rematch_max_rating_increase: i64,
182
183    #[schemars(title = "Максимальное уменьшение рейтинга в рематче")]
184    pub rematch_max_rating_decrease: i64,
185
186    // --- Асимметричный обмен очков (кайф-матчмейкинг) ---
187    // Тип цели определяется отношением силы противника к силе атакующего в
188    // момент боя (сила — канонический честный скаляр): ниже prey-порога —
189    // «добыча», выше stretch-порога — «дерзость», между ними — «ровня».
190    #[schemars(title = "Порог силы «добычи»: противник слабее этой доли силы игрока")]
191    #[serde(default = "default_rating_prey_ratio")]
192    pub rating_prey_power_ratio: f64,
193
194    #[schemars(title = "Порог силы «дерзости»: противник сильнее этой доли силы игрока")]
195    #[serde(default = "default_rating_stretch_ratio")]
196    pub rating_stretch_power_ratio: f64,
197
198    #[schemars(title = "Очки за победу над «добычей»")]
199    #[serde(default = "default_win_points_prey")]
200    pub win_points_prey: i64,
201
202    #[schemars(title = "Очки за победу над «ровней»")]
203    #[serde(default = "default_win_points_peer")]
204    pub win_points_peer: i64,
205
206    #[schemars(title = "Очки за победу над «дерзостью»")]
207    #[serde(default = "default_win_points_stretch")]
208    pub win_points_stretch: i64,
209
210    // Потеря тоже асимметрична: слить «добыче» (слабее тебя) — дорого,
211    // слить «дерзости» (сильнее тебя) — почти бесплатно.
212    #[schemars(title = "Потеря очков за поражение «добыче» (положительное число)")]
213    #[serde(default = "default_lose_points_prey")]
214    pub lose_points_prey: i64,
215
216    #[schemars(title = "Потеря очков за поражение «ровне» (положительное число)")]
217    #[serde(default = "default_lose_points_peer")]
218    pub lose_points_peer: i64,
219
220    #[schemars(title = "Потеря очков за поражение «дерзости» (положительное число)")]
221    #[serde(default = "default_lose_points_stretch")]
222    pub lose_points_stretch: i64,
223
224    #[schemars(title = "Защита новичка: ниже этого рейтинга поражение не отнимает очки")]
225    #[serde(default = "default_lose_protection_rating")]
226    pub lose_protection_rating: i64,
227
228    #[schemars(title = "Бонус очков за каждую победу в серии (сверх первой)")]
229    #[serde(default = "default_win_streak_bonus_step")]
230    pub win_streak_bonus_step: i64,
231
232    #[schemars(title = "Максимальный суммарный бонус за победную серию")]
233    #[serde(default = "default_win_streak_bonus_max")]
234    pub win_streak_bonus_max: i64,
235
236    #[schemars(
237        title = "Защита от серий поражений: после скольких поражений подряд гарантировать «добычу» в списке подбора"
238    )]
239    #[serde(default = "default_loss_streak_protection_after")]
240    pub loss_streak_protection_after: i64,
241}
242
243// Defaults preserve a sane ladder even when the config predates the fields;
244// the flat legacy (+10/−5) is superseded by the asymmetric table.
245fn default_rating_prey_ratio() -> f64 {
246    0.85
247}
248fn default_rating_stretch_ratio() -> f64 {
249    1.10
250}
251fn default_win_points_prey() -> i64 {
252    5
253}
254fn default_win_points_peer() -> i64 {
255    9
256}
257fn default_win_points_stretch() -> i64 {
258    14
259}
260fn default_lose_points_prey() -> i64 {
261    8
262}
263fn default_lose_points_peer() -> i64 {
264    5
265}
266fn default_lose_points_stretch() -> i64 {
267    2
268}
269fn default_lose_protection_rating() -> i64 {
270    1100
271}
272fn default_win_streak_bonus_step() -> i64 {
273    1
274}
275fn default_win_streak_bonus_max() -> i64 {
276    5
277}
278fn default_loss_streak_protection_after() -> i64 {
279    2
280}