configs/
tests_game_config.rs

1use essences::{
2    abilities::{
3        AbilityCastType, AbilityFightUiVisibility, AbilityRarity, AbilityTargetType,
4        AbilityTemplate,
5    },
6    ability_presets, bundles, class,
7    currency::{Currency, CurrencyUnit},
8    dungeons::{DungeonTemplate, DungeonTip, RewardType},
9    effect::Effect,
10    entity::Coordinates,
11    fighting::{
12        EntityTeam, EntityType, FightEntity, FightTemplate, FightType, PrepareFightEntityPower,
13        PrepareFightSpawn, PrepareFightWaves,
14    },
15    game::{
16        AbilitySlotsLevel, Chapter, CharacterLevel, EnemyReward, EntityAttribute, EntityTemplate,
17        PetSlotsLevel,
18    },
19    gatings::{AutoChestGatings, CastleGating, Gatings, NavBarNavigation, SideBarNavigation},
20    generation::{
21        BotsSettings, PhotoGenerationSettings, UsernameGenerationSettings, UsersGeneratingSettings,
22    },
23    gift::{GiftTemplate, GiftType},
24    item_case::{
25        AutoChestSettings, InventoryLevel, ItemCaseRarityWeight, ItemCasesSettingsByLevel,
26    },
27    items::{Attribute, ItemAttributeSettings, ItemRarity, ItemTemplate, ItemType},
28    mail::{MailRepeatType, MailSendType, MailTemplate},
29    offers::{OfferTemplate, PaymentType, ShopTab, ShopTabConfig},
30    pets::{PetRarity, PetSecondaryStat, PetTemplate},
31    quest::{
32        QuestGroupType, QuestTemplate, QuestsProgressionPointSettings, QuestsProgressionSettings,
33    },
34    ratings::{RatingRangeReward, RatingSettings, RatingType},
35    referrals::ReferralLevelInfo,
36    skins::{ConfigSkin, SkinType, SkinsSettings},
37    vassals::VassalTaskTemplate,
38};
39
40use uuid::{Uuid, uuid};
41
42use enum_iterator::all;
43
44use crate::statue::{
45    StatueBonusGradeValue, StatueBonusGradeWeight, StatueBonusTypeConfig, StatueLevelConfig,
46    StatueRollCostConfig, StatueSettings,
47};
48use crate::validated_types::{
49    NonEmptyVec, NonZeroU64, PositiveF64, PositiveI32, PositiveI64, WeightMultiplier,
50};
51use crate::{
52    abilities::{
53        AbilityCaseCheckpointAbilityReward, AbilityCaseCheckpointReward, AbilityCaseEvolveRule,
54        AbilityCaseRarityWeight, AbilityCasesSettingsByLevel, AbilityLevel, BigRollShard,
55        Projectile,
56    },
57    ads_settings::{AdSpeedupConfig, AdsSettings, BirdAdConfig, BirdAdVariantWeight, BirdVariant},
58    afk_rewards::{
59        AfkRewardBonusType, AfkRewardBonusWeight, AfkRewardsByLevel, AfkRewardsSettings,
60        CurrencyRate,
61    },
62    buffs::{BuffEffect, BuffTemplate},
63    events::EventDescription,
64    fighting::{ArenaLeague, ArenaSettings, FightSettings, PvpSettings},
65    game_config::GameConfig,
66    game_settings::{DailyCurrencyReset, GameSettings},
67    matchmaking::{MatchmakingSettings, OpponentPositionSettings},
68    pets::{
69        PetBigRollShard, PetCaseCheckpointPetReward, PetCaseCheckpointReward, PetCaseRarityWeight,
70        PetCasesSettingsByLevel, PetLevel,
71    },
72    reports::ReportsSettings,
73    vassals::VassalsSettings,
74};
75use essences::progress_pass::{ProgressPassConfig, ProgressPassTierTemplate};
76use essences::statue::StatueBonusGrade;
77use essences::talent_tree::{
78    TalentAttributeBonus, TalentBackendModifier, TalentLevel, TalentPosition, TalentTemplate,
79    TalentTreeSettings, TalentUnlockCondition,
80};
81
82fn generate_attributes() -> Vec<Attribute> {
83    vec![
84        Attribute {
85            id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
86            name: i18n::I18nString::new(
87                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
88            ),
89            prefix: Some(i18n::I18nString::new(
90                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
91            )),
92            suffix: Some(i18n::I18nString::new(
93                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
94            )),
95            code: "hp".to_string(),
96            icon: "/hp_icon.webp".to_string(),
97            icon_path: "/hp_icon.webp".to_string(),
98            db_code: 0,
99            denominator: None,
100            is_percent: false,
101            // Native item-attribute fn required by `try_finalize_item`
102            // (bot/gacha item generation). `hp` is a required attribute, so
103            // generated items always finalize it. Maps to the `attr_health` port.
104            calculation_behavior: Some("attr_health".to_string()),
105            order: 0,
106            is_ui_visible: true,
107            base_value: None,
108            description: i18n::I18nString::new(
109                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
110            ),
111        },
112        Attribute {
113            id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
114            name: i18n::I18nString::new(
115                "content.attributes.6ad485d7-9567-4b77-8ddc-a2418dd1dfe6:name",
116            ),
117            prefix: Some(i18n::I18nString::new(
118                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
119            )),
120            suffix: Some(i18n::I18nString::new(
121                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
122            )),
123            code: "damage".to_string(),
124            icon: "/damage_icon.webp".to_string(),
125            icon_path: "/damage_icon.webp".to_string(),
126            db_code: 1,
127            is_percent: false,
128            denominator: None,
129            // `damage` is also a required attribute -> finalized on every
130            // generated item. Maps to the `attr_damage` port.
131            calculation_behavior: Some("attr_damage".to_string()),
132            order: 1,
133            is_ui_visible: true,
134            base_value: None,
135            description: i18n::I18nString::new(
136                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
137            ),
138        },
139        Attribute {
140            id: uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d"),
141            name: i18n::I18nString::new(
142                "content.attributes.3a6ec1c8-7494-43df-a345-d23e297b892d:name",
143            ),
144            prefix: Some(i18n::I18nString::new(
145                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
146            )),
147            suffix: Some(i18n::I18nString::new(
148                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
149            )),
150            code: "strength".to_string(),
151            icon: "/strength_icon.webp".to_string(),
152            icon_path: "/strength_icon.webp".to_string(),
153            db_code: 2,
154            is_percent: false,
155            denominator: None,
156            // Not a required/optional attribute on test item templates, so not
157            // finalized in practice; map to a registered fn for completeness.
158            calculation_behavior: Some("attr_zero".to_string()),
159            order: 2,
160            is_ui_visible: true,
161            base_value: None,
162            description: i18n::I18nString::new(
163                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
164            ),
165        },
166        Attribute {
167            id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
168            name: i18n::I18nString::new(
169                "content.attributes.42aea610-2ab7-41f7-95bf-5d6f00341ac9:name",
170            ),
171            prefix: Some(i18n::I18nString::new(
172                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
173            )),
174            suffix: Some(i18n::I18nString::new(
175                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
176            )),
177            code: "agility".to_string(),
178            icon: "/agility_icon.webp".to_string(),
179            icon_path: "/agility_icon.webp".to_string(),
180            db_code: 3,
181            is_percent: false,
182            denominator: None,
183            calculation_behavior: Some("attr_zero".to_string()),
184            order: 3,
185            is_ui_visible: true,
186            base_value: None,
187            description: i18n::I18nString::new(
188                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
189            ),
190        },
191        Attribute {
192            id: uuid!("f82eb3fa-8a09-44fb-b8ed-979cc2db28f4"),
193            name: i18n::I18nString::new(
194                "content.attributes.f82eb3fa-8a09-44fb-b8ed-979cc2db28f4:name",
195            ),
196            prefix: Some(i18n::I18nString::new(
197                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
198            )),
199            suffix: Some(i18n::I18nString::new(
200                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
201            )),
202            code: "armor".to_string(),
203            icon: "/armor_icon.webp".to_string(),
204            icon_path: "/armor_icon.webp".to_string(),
205            db_code: 4,
206            is_percent: false,
207            denominator: None,
208            // Maps to the `attr_armor` port (optional attribute on some items).
209            calculation_behavior: Some("attr_armor".to_string()),
210            order: 4,
211            is_ui_visible: false,
212            base_value: None,
213            description: i18n::I18nString::new(
214                "content.attributes.45eca0a7-7430-487b-bd65-b796c6d88c08:name",
215            ),
216        },
217    ]
218}
219
220fn generate_item_cases_settings() -> Vec<ItemCasesSettingsByLevel> {
221    vec![
222        ItemCasesSettingsByLevel {
223            level: 1,
224            required_chapter_level: 0,
225            upgrade_cost: vec![],
226            upgrade_time_secs: 600,
227            rarity_weights: vec![
228                ItemCaseRarityWeight {
229                    rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
230                    weight: 512.0,
231                },
232                ItemCaseRarityWeight {
233                    rarity_id: uuid!("272f3e73-6b3e-43a0-88d6-d34bdaf5aeae"),
234                    weight: 256.0,
235                },
236                ItemCaseRarityWeight {
237                    rarity_id: uuid!("c45eed5f-ad7e-4af0-b0a5-46b311573bf4"),
238                    weight: 128.0,
239                },
240                ItemCaseRarityWeight {
241                    rarity_id: uuid!("a9a0575f-9d09-4118-b305-14e927817302"),
242                    weight: 64.0,
243                },
244                ItemCaseRarityWeight {
245                    rarity_id: uuid!("19e2db05-5f17-4d89-9732-924134056776"),
246                    weight: 32.0,
247                },
248                ItemCaseRarityWeight {
249                    rarity_id: uuid!("9d662020-0929-439b-8afa-f286b72070a9"),
250                    weight: 16.0,
251                },
252                ItemCaseRarityWeight {
253                    rarity_id: uuid!("363dded9-e5a4-4bb9-bde6-63037d808246"),
254                    weight: 8.0,
255                },
256                ItemCaseRarityWeight {
257                    rarity_id: uuid!("9e1842cc-4192-4332-8c13-0f901ca442a4"),
258                    weight: 4.0,
259                },
260                ItemCaseRarityWeight {
261                    rarity_id: uuid!("d59e98d8-fc7d-4b8b-9da0-a374400df154"),
262                    weight: 0.0,
263                },
264                ItemCaseRarityWeight {
265                    rarity_id: uuid!("c0d049eb-359e-4b1e-9de2-eda276043ea8"),
266                    weight: 0.0,
267                },
268            ],
269            auto_chest_settings: AutoChestSettings { max_batch_size: 2 },
270        },
271        ItemCasesSettingsByLevel {
272            level: 2,
273            required_chapter_level: 0,
274            upgrade_cost: vec![CurrencyUnit {
275                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
276                amount: 20,
277            }],
278            upgrade_time_secs: 600,
279            rarity_weights: vec![
280                ItemCaseRarityWeight {
281                    rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
282                    weight: 256.0,
283                },
284                ItemCaseRarityWeight {
285                    rarity_id: uuid!("272f3e73-6b3e-43a0-88d6-d34bdaf5aeae"),
286                    weight: 256.0,
287                },
288                ItemCaseRarityWeight {
289                    rarity_id: uuid!("c45eed5f-ad7e-4af0-b0a5-46b311573bf4"),
290                    weight: 128.0,
291                },
292                ItemCaseRarityWeight {
293                    rarity_id: uuid!("a9a0575f-9d09-4118-b305-14e927817302"),
294                    weight: 64.0,
295                },
296                ItemCaseRarityWeight {
297                    rarity_id: uuid!("19e2db05-5f17-4d89-9732-924134056776"),
298                    weight: 32.0,
299                },
300                ItemCaseRarityWeight {
301                    rarity_id: uuid!("9d662020-0929-439b-8afa-f286b72070a9"),
302                    weight: 16.0,
303                },
304                ItemCaseRarityWeight {
305                    rarity_id: uuid!("363dded9-e5a4-4bb9-bde6-63037d808246"),
306                    weight: 8.0,
307                },
308                ItemCaseRarityWeight {
309                    rarity_id: uuid!("9e1842cc-4192-4332-8c13-0f901ca442a4"),
310                    weight: 4.0,
311                },
312                ItemCaseRarityWeight {
313                    rarity_id: uuid!("d59e98d8-fc7d-4b8b-9da0-a374400df154"),
314                    weight: 0.0,
315                },
316                ItemCaseRarityWeight {
317                    rarity_id: uuid!("c0d049eb-359e-4b1e-9de2-eda276043ea8"),
318                    weight: 0.0,
319                },
320            ],
321            auto_chest_settings: AutoChestSettings { max_batch_size: 2 },
322        },
323        ItemCasesSettingsByLevel {
324            level: 3,
325            required_chapter_level: 5,
326            upgrade_cost: vec![CurrencyUnit {
327                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
328                amount: 20,
329            }],
330            upgrade_time_secs: 600,
331            rarity_weights: vec![
332                ItemCaseRarityWeight {
333                    rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
334                    weight: 256.0,
335                },
336                ItemCaseRarityWeight {
337                    rarity_id: uuid!("272f3e73-6b3e-43a0-88d6-d34bdaf5aeae"),
338                    weight: 256.0,
339                },
340                ItemCaseRarityWeight {
341                    rarity_id: uuid!("c45eed5f-ad7e-4af0-b0a5-46b311573bf4"),
342                    weight: 128.0,
343                },
344                ItemCaseRarityWeight {
345                    rarity_id: uuid!("a9a0575f-9d09-4118-b305-14e927817302"),
346                    weight: 64.0,
347                },
348                ItemCaseRarityWeight {
349                    rarity_id: uuid!("19e2db05-5f17-4d89-9732-924134056776"),
350                    weight: 32.0,
351                },
352                ItemCaseRarityWeight {
353                    rarity_id: uuid!("9d662020-0929-439b-8afa-f286b72070a9"),
354                    weight: 16.0,
355                },
356                ItemCaseRarityWeight {
357                    rarity_id: uuid!("363dded9-e5a4-4bb9-bde6-63037d808246"),
358                    weight: 8.0,
359                },
360                ItemCaseRarityWeight {
361                    rarity_id: uuid!("9e1842cc-4192-4332-8c13-0f901ca442a4"),
362                    weight: 4.0,
363                },
364                ItemCaseRarityWeight {
365                    rarity_id: uuid!("d59e98d8-fc7d-4b8b-9da0-a374400df154"),
366                    weight: 2.0,
367                },
368                ItemCaseRarityWeight {
369                    rarity_id: uuid!("c0d049eb-359e-4b1e-9de2-eda276043ea8"),
370                    weight: 1.0,
371                },
372            ],
373            auto_chest_settings: AutoChestSettings { max_batch_size: 3 },
374        },
375    ]
376}
377
378fn generate_game_settings() -> GameSettings {
379    GameSettings {
380        required_attributes: vec![
381            uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
382            uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
383        ],
384        resist_task_id: uuid!("05e915bf-55fe-4419-bcf0-5f90833f17bd"),
385        hp_attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
386        time_skip_ticket_currency_id: uuid!("22297520-abb8-45b9-9fbb-c418b8001246"),
387        chest_upgrade_skip_ticket_skips_sec: 750,
388        chest_upgrade_skip_currency_id: uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
389        chest_upgrade_skip_currency_skips_sec: 400,
390        ability_gacha: crate::game_settings::AbilityGachaSettings {
391            currency_id: uuid!("22297520-abb8-45b9-9fbb-c418b8001246"),
392            roll_price_in_diamonds: PositiveI64::new(2),
393            small_roll_cost: PositiveI64::new(3),
394            big_roll_cost: PositiveI64::new(10),
395            big_roll_bonus_drops: 1,
396            wishlist_slots: 5,
397            wishlist_weight_multiplier: WeightMultiplier::new(2.0),
398            slot_upgrade_currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
399            slot_max_level: PositiveI64::new(6),
400            slot_level_costs: vec![
401                PositiveI64::new(100),
402                PositiveI64::new(200),
403                PositiveI64::new(300),
404                PositiveI64::new(400),
405                PositiveI64::new(500),
406                PositiveI64::new(600),
407            ],
408            slot_level_bonus_levels: vec![0, 1, 2, 3, 4, 5, 6],
409        },
410        default_loop_task_behavior: "test_default_loop_task".to_string(),
411        item_case_currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
412        initial_class_id: uuid!("00000000-0000-0000-0000-000000000000"),
413        chat_message_ttl_secs: 3600,
414        baseline_speed: 10_000,
415        currency_ids_to_show: vec![
416            uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
417            uuid!("22297520-abb8-45b9-9fbb-c418b8001246"),
418            uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
419        ],
420        auto_chest_pause_duration_ticks: 20,
421        arena_fight_template_id: uuid!("360fc654-dea1-4f5d-97af-249ab30608ac"),
422        vassal_fight_id: uuid!("b92c69a2-6544-4b83-809f-5af290b75473"),
423        fight_progress_tick: 1000,
424        db_power_update_frequency: 2,
425        deleted_user_username: "Deleted".to_owned(),
426        diamond_currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
427        username_change_cooldown_sec: 604800,
428        username_min_length: 3,
429        username_max_length: 32,
430        dungeons_keys_reset_amount: 2,
431        daily_currency_resets: vec![
432            DailyCurrencyReset {
433                currency_id: uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
434                reset_amount: 5,
435            },
436            // Regression fixture for the day-1 spurious-refill bug. Unlike the
437            // arena-ticket entry above (whose reset row is seeded at character
438            // creation), this currency is intentionally NOT granted/seeded at
439            // creation, so a fresh character holds 0 of it with no reset
440            // record — the exact shape production dungeon keys have. A fresh
441            // character must NOT have it refilled on its creation day. Test-only
442            // id; referenced solely by test_daily_currency_reset_* tests.
443            DailyCurrencyReset {
444                currency_id: uuid!("0da11000-0000-0000-0000-000000000001"),
445                reset_amount: 3,
446            },
447        ],
448        pet_gacha: crate::game_settings::PetGachaSettings {
449            currency_id: uuid!("22297520-abb8-45b9-9fbb-c418b8001246"),
450            roll_price_in_diamonds: PositiveI64::new(2),
451            small_roll_cost: PositiveI64::new(3),
452            big_roll_cost: PositiveI64::new(10),
453            big_roll_bonus_drops: 1,
454            wishlist_slots: 5,
455            wishlist_weight_multiplier: WeightMultiplier::new(2.0),
456        },
457        default_shop_tab: ShopTab::DailyDeals,
458        rate_us_chapter: None,
459        boss_reward_chapter_growth: None,
460        boss_reward_max_multiplier: None,
461    }
462}
463
464fn generate_ads_settings() -> AdsSettings {
465    AdsSettings {
466        chest_upgrade_speedup: AdSpeedupConfig {
467            speedup_seconds: 300,
468            cooldown_sec: 5,
469            daily_limit: 3,
470        },
471        talent_upgrade_speedup: AdSpeedupConfig {
472            speedup_seconds: 300,
473            cooldown_sec: 5,
474            daily_limit: 3,
475        },
476        free_ability_case_cooldown_sec: 86400,
477        skill_gacha_ad_daily_limit: 3,
478        skill_gacha_ad_rolls: 3,
479        pet_gacha_ad_daily_limit: 3,
480        pet_gacha_ad_rolls: 3,
481        afk_boost_ad_daily_limit: 1,
482        afk_boost_multiplier: 1.5,
483        daily_booster_ad_daily_limit: 1,
484        daily_booster_ad_buff_template_id: uuid!("b2c3d4e5-f6a7-8901-bcde-f12345678901"),
485        daily_booster_ad_buff_duration: 3600,
486        arena_refresh_ad_daily_limit: 3,
487        dungeon_raid_ad_daily_limit: 2,
488        bird_ad: BirdAdConfig {
489            daily_limit: 5,
490            cooldown_sec: 60,
491            post_show_cooldown_sec: 10,
492            flight_duration_sec: 8,
493            variants: vec![
494                BirdAdVariantWeight {
495                    variant_id: uuid!("d1e2f3a4-b5c6-7890-abcd-ef1234567891"),
496                    weight: 70,
497                },
498                BirdAdVariantWeight {
499                    variant_id: uuid!("d1e2f3a4-b5c6-7890-abcd-ef1234567892"),
500                    weight: 30,
501                },
502            ],
503        },
504    }
505}
506
507fn generate_item_rarities() -> Vec<ItemRarity> {
508    vec![
509        ItemRarity {
510            id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
511            code: 1,
512            name: i18n::I18nString::new(
513                "content.item_rarities.8c8acba2-67d3-40e0-ac62-2f7acce64ccc:name",
514            ),
515            rarity_icon: "2b51dc17-022f-404d-a31b-6a7fe1d8603a.png".to_string(),
516            rarity_icon_path: "2b51dc17-022f-404d-a31b-6a7fe1d8603a.png".to_string(),
517            text_color: "#E9E9D4".to_string(),
518            ribbon_icon: "".to_string(),
519            ribbon_icon_path: "".to_string(),
520            order: 1,
521            q: 1,
522        },
523        ItemRarity {
524            id: uuid!("272f3e73-6b3e-43a0-88d6-d34bdaf5aeae"),
525            code: 2,
526            name: i18n::I18nString::new(
527                "content.item_rarities.272f3e73-6b3e-43a0-88d6-d34bdaf5aeae:name",
528            ),
529            rarity_icon: "df3529d5-9a9a-4399-9f16-34ea61b66c93.png".to_string(),
530            rarity_icon_path: "df3529d5-9a9a-4399-9f16-34ea61b66c93.png".to_string(),
531            text_color: "#36DB89".to_string(),
532            ribbon_icon: "".to_string(),
533            ribbon_icon_path: "".to_string(),
534            order: 2,
535            q: 1,
536        },
537        ItemRarity {
538            id: uuid!("c45eed5f-ad7e-4af0-b0a5-46b311573bf4"),
539            code: 3,
540            name: i18n::I18nString::new(
541                "content.item_rarities.c45eed5f-ad7e-4af0-b0a5-46b311573bf4:name",
542            ),
543            rarity_icon: "28d57678-8db0-4870-9791-1899b7228f96.png".to_string(),
544            rarity_icon_path: "28d57678-8db0-4870-9791-1899b7228f96.png".to_string(),
545            text_color: "#399AE1".to_string(),
546            ribbon_icon: "".to_string(),
547            ribbon_icon_path: "".to_string(),
548            order: 3,
549            q: 1,
550        },
551        ItemRarity {
552            id: uuid!("a9a0575f-9d09-4118-b305-14e927817302"),
553            code: 4,
554            name: i18n::I18nString::new(
555                "content.item_rarities.a9a0575f-9d09-4118-b305-14e927817302:name",
556            ),
557            rarity_icon: "b08a1167-c58d-42a4-8230-576c3b69063c.png".to_string(),
558            rarity_icon_path: "b08a1167-c58d-42a4-8230-576c3b69063c.png".to_string(),
559            text_color: "#CC34E3".to_string(),
560            ribbon_icon: "".to_string(),
561            ribbon_icon_path: "".to_string(),
562            order: 4,
563            q: 1,
564        },
565        ItemRarity {
566            id: uuid!("19e2db05-5f17-4d89-9732-924134056776"),
567            code: 5,
568            name: i18n::I18nString::new(
569                "content.item_rarities.19e2db05-5f17-4d89-9732-924134056776:name",
570            ),
571            rarity_icon: "1edfd7ed-8945-4c95-8bd5-40ba9422d7c2.png".to_string(),
572            rarity_icon_path: "1edfd7ed-8945-4c95-8bd5-40ba9422d7c2.png".to_string(),
573            text_color: "#FDCA5B".to_string(),
574            ribbon_icon: "".to_string(),
575            ribbon_icon_path: "".to_string(),
576            order: 5,
577            q: 1,
578        },
579        ItemRarity {
580            id: uuid!("9d662020-0929-439b-8afa-f286b72070a9"),
581            code: 6,
582            name: i18n::I18nString::new(
583                "content.item_rarities.9d662020-0929-439b-8afa-f286b72070a9:name",
584            ),
585            rarity_icon: "60b73aa0-c1dd-4bac-9efe-ebc25030dbef.png".to_string(),
586            rarity_icon_path: "60b73aa0-c1dd-4bac-9efe-ebc25030dbef.png".to_string(),
587            text_color: "#F78B46".to_string(),
588            ribbon_icon: "".to_string(),
589            ribbon_icon_path: "".to_string(),
590            order: 6,
591            q: 1,
592        },
593        ItemRarity {
594            id: uuid!("363dded9-e5a4-4bb9-bde6-63037d808246"),
595            code: 7,
596            name: i18n::I18nString::new(
597                "content.item_rarities.363dded9-e5a4-4bb9-bde6-63037d808246:name",
598            ),
599            rarity_icon: "59126b12-2d5c-45f4-8f58-1283f6ba9ccd.png".to_string(),
600            rarity_icon_path: "59126b12-2d5c-45f4-8f58-1283f6ba9ccd.png".to_string(),
601            text_color: "#ED581D".to_string(),
602            ribbon_icon: "".to_string(),
603            ribbon_icon_path: "".to_string(),
604            order: 7,
605            q: 1,
606        },
607        ItemRarity {
608            id: uuid!("9e1842cc-4192-4332-8c13-0f901ca442a4"),
609            code: 8,
610            name: i18n::I18nString::new(
611                "content.item_rarities.9e1842cc-4192-4332-8c13-0f901ca442a4:name",
612            ),
613            rarity_icon: "5dbec395-33dd-43da-b35a-8d1262409c9d.png".to_string(),
614            rarity_icon_path: "5dbec395-33dd-43da-b35a-8d1262409c9d.png".to_string(),
615            text_color: "#FA91FF".to_string(),
616            ribbon_icon: "".to_string(),
617            ribbon_icon_path: "".to_string(),
618            order: 8,
619            q: 1,
620        },
621        ItemRarity {
622            id: uuid!("d59e98d8-fc7d-4b8b-9da0-a374400df154"),
623            code: 9,
624            name: i18n::I18nString::new(
625                "content.item_rarities.d59e98d8-fc7d-4b8b-9da0-a374400df154:name",
626            ),
627            rarity_icon: "0d0a6bfa-d2db-40bc-88c9-3bce4472e376.png".to_string(),
628            rarity_icon_path: "0d0a6bfa-d2db-40bc-88c9-3bce4472e376.png".to_string(),
629            text_color: "#5FECF3".to_string(),
630            ribbon_icon: "".to_string(),
631            ribbon_icon_path: "".to_string(),
632            order: 9,
633            q: 1,
634        },
635        ItemRarity {
636            id: uuid!("c0d049eb-359e-4b1e-9de2-eda276043ea8"),
637            code: 10,
638            name: i18n::I18nString::new(
639                "content.item_rarities.c0d049eb-359e-4b1e-9de2-eda276043ea8:name",
640            ),
641            rarity_icon: "b4e58214-77c1-45fa-a1ec-260c1e76b5cd.png".to_string(),
642            rarity_icon_path: "b4e58214-77c1-45fa-a1ec-260c1e76b5cd.png".to_string(),
643            text_color: "#E73636".to_string(),
644            ribbon_icon: "".to_string(),
645            ribbon_icon_path: "".to_string(),
646            order: 10,
647            q: 1,
648        },
649    ]
650}
651
652fn generate_effects() -> Vec<Effect> {
653    vec![
654        Effect {
655            id: uuid!("ccc47912-61c0-4efa-88f9-7911fa1b074f"),
656            name: i18n::I18nString::new(
657                "content.effects.ccc47912-61c0-4efa-88f9-7911fa1b074f:name",
658            ),
659            behavior: Some("bloodleak_tick".to_string()),
660            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
661            interval_ticks: Some(5000),
662            required_attributes: Some(vec!["bloodleak".to_string()]),
663            events_subscribe: None,
664            positive: false,
665            code: "".into(),
666            icon_path: "".into(),
667            vfx_path: "".into(),
668            duration: None,
669        },
670        Effect {
671            id: uuid!("3b136901-137c-47cc-8c7e-bc0ce387eb1c"),
672            name: i18n::I18nString::new(
673                "content.effects.3b136901-137c-47cc-8c7e-bc0ce387eb1c:name",
674            ),
675            behavior: Some("low_hp_heal_on_damage".to_string()),
676            icon_url: "8e991eae-e001-4a76-8238-277c38b35889.webp".to_string(),
677            interval_ticks: None,
678            required_attributes: None,
679            events_subscribe: Some(vec!["Damage".to_string()]),
680            positive: true,
681            code: "".into(),
682            icon_path: "".into(),
683            vfx_path: "".into(),
684            duration: None,
685        },
686        Effect {
687            id: uuid!("39f135d2-b930-42a7-abfa-f1ec49f3cc00"),
688            name: i18n::I18nString::new(
689                "content.effects.3b136901-137c-47cc-8c7e-bc0ce387eb1c:name",
690            ),
691            behavior: Some("spawn_two_on_death".to_string()),
692            icon_url: "8e991eae-e001-4a76-8238-277c38b35889.webp".to_string(),
693            interval_ticks: None,
694            required_attributes: None,
695            events_subscribe: Some(vec!["EntityDeath".to_string()]),
696            positive: true,
697            code: "".into(),
698            icon_path: "".into(),
699            vfx_path: "".into(),
700            duration: None,
701        },
702    ]
703}
704
705fn generate_abilities() -> Vec<AbilityTemplate> {
706    vec![
707        AbilityTemplate {
708            id: uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac"),
709            is_fight_ui_visible: false,
710            fight_ui_visibility: AbilityFightUiVisibility::Hidden,
711            name: i18n::I18nString::new(
712                "content.abilities.da6c582b-7364-40bd-9b2d-946d8e20eaac:name",
713            ),
714            start_behavior: Some("attack_first_enemy".to_string()),
715            behavior: Some("ability_damage_target_5".to_string()),
716            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
717            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
718            cooldown: 10000,
719            is_gacha_ability: false,
720            available_to_bots: true,
721            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
722            description: i18n::I18nString::new(
723                "content.abilities.da6c582b-7364-40bd-9b2d-946d8e20eaac:description",
724            ),
725            description_values_script: Some("Result.push(1); Result.push(100)".to_string()),
726            vfx_object_path: "".into(),
727            cast_type: AbilityCastType::default(),
728            target_type: AbilityTargetType::default(),
729            range: 1,
730        },
731        AbilityTemplate {
732            id: uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a"),
733            is_fight_ui_visible: true,
734            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
735            name: i18n::I18nString::new(
736                "content.abilities.7e584338-057d-41a2-a80e-8e2c76e98f6a:name",
737            ),
738            start_behavior: Some("attack_first_enemy".to_string()),
739            behavior: Some("ability_damage_target_5".to_string()),
740            icon_url: "8e991eae-e001-4a76-8238-277c38b35889.webp".to_string(),
741            icon_path: "8e991eae-e001-4a76-8238-277c38b35889.webp".to_string(),
742            cooldown: 30000,
743            is_gacha_ability: true,
744            available_to_bots: true,
745            rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
746            description: i18n::I18nString::new(
747                "content.abilities.7e584338-057d-41a2-a80e-8e2c76e98f6a:description",
748            ),
749            description_values_script: Some(
750                "Result.push(2); Result.push(200); Result.push(20000)".to_string(),
751            ),
752            vfx_object_path: "".into(),
753            cast_type: AbilityCastType::default(),
754            target_type: AbilityTargetType::default(),
755            range: 1,
756        },
757        AbilityTemplate {
758            id: uuid!("487a23e5-7401-4c34-a6c6-2401f95249cf"),
759            is_fight_ui_visible: true,
760            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
761            name: i18n::I18nString::new(
762                "content.abilities.487a23e5-7401-4c34-a6c6-2401f95249cf:name",
763            ),
764            start_behavior: Some("attack_first_enemy".to_string()),
765            behavior: Some("ability_damage_target_5".to_string()),
766            icon_url: "2cd222a0-1a1a-42d2-b553-7d3754b08e0d.webp".to_string(),
767            icon_path: "2cd222a0-1a1a-42d2-b553-7d3754b08e0d.webp".to_string(),
768            cooldown: 15000,
769            is_gacha_ability: true,
770            available_to_bots: true,
771            rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
772            description: i18n::I18nString::new(
773                "content.abilities.487a23e5-7401-4c34-a6c6-2401f95249cf:description",
774            ),
775            description_values_script: Some("Result.push(3);".to_string()),
776            vfx_object_path: "".into(),
777            cast_type: AbilityCastType::default(),
778            target_type: AbilityTargetType::default(),
779            range: 1,
780        },
781        AbilityTemplate {
782            id: uuid!("fd053ec6-8b23-4ba1-a31f-31b56d8c57bc"),
783            is_fight_ui_visible: true,
784            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
785            name: i18n::I18nString::new(
786                "content.abilities.fd053ec6-8b23-4ba1-a31f-31b56d8c57bc:name",
787            ),
788            start_behavior: Some("attack_first_enemy".to_string()),
789            behavior: Some("ability_damage_target_5".to_string()),
790            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
791            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
792            cooldown: 10000,
793            is_gacha_ability: true,
794            available_to_bots: true,
795            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
796            description: i18n::I18nString::new(
797                "content.abilities.fd053ec6-8b23-4ba1-a31f-31b56d8c57bc:description",
798            ),
799            description_values_script: None,
800            vfx_object_path: "".into(),
801            cast_type: AbilityCastType::default(),
802            target_type: AbilityTargetType::default(),
803            range: 1,
804        },
805        AbilityTemplate {
806            id: uuid!("50260b1c-7748-49bf-a1ed-34d69d029697"),
807            is_fight_ui_visible: true,
808            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
809            name: i18n::I18nString::new(
810                "content.abilities.50260b1c-7748-49bf-a1ed-34d69d029697:name",
811            ),
812            start_behavior: Some("attack_first_enemy".to_string()),
813            behavior: Some("ability_apply_bloodleak_effect".to_string()),
814            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
815            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
816            cooldown: 10000,
817            is_gacha_ability: false,
818            available_to_bots: true,
819            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
820            description: i18n::I18nString::new(
821                "content.abilities.50260b1c-7748-49bf-a1ed-34d69d029697:description",
822            ),
823            description_values_script: Some("Result.push(5); Result.push(500)".to_string()),
824            vfx_object_path: "".into(),
825            cast_type: AbilityCastType::default(),
826            target_type: AbilityTargetType::default(),
827            range: 1,
828        },
829        AbilityTemplate {
830            id: uuid!("41ee5532-a293-4f88-bfb6-5ffca1e57acc"),
831            is_fight_ui_visible: true,
832            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
833            name: i18n::I18nString::new(
834                "content.abilities.41ee5532-a293-4f88-bfb6-5ffca1e57acc:name",
835            ),
836            start_behavior: Some("self_attack_500".to_string()),
837            behavior: Some("ability_apply_low_hp_heal_effect".to_string()),
838            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
839            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
840            cooldown: 10000,
841            is_gacha_ability: false,
842            available_to_bots: true,
843            rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
844            description: i18n::I18nString::new(
845                "content.abilities.41ee5532-a293-4f88-bfb6-5ffca1e57acc:description",
846            ),
847            description_values_script: Some("Result.push(6); Result.push(600)".to_string()),
848            vfx_object_path: "".into(),
849            cast_type: AbilityCastType::default(),
850            target_type: AbilityTargetType::default(),
851            range: 1,
852        },
853        AbilityTemplate {
854            id: uuid!("9f8e7d6c-5b4a-3c2d-1e0f-9a8b7c6d5e4f"),
855            is_fight_ui_visible: true,
856            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
857            name: i18n::I18nString::new(
858                "content.abilities.9f8e7d6c-5b4a-3c2d-1e0f-9a8b7c6d5e4f:name",
859            ),
860            start_behavior: Some("attack_first_enemy".to_string()),
861            behavior: Some("ability_damage_target_5".to_string()),
862            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
863            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
864            cooldown: 0,
865            is_gacha_ability: true,
866            available_to_bots: true,
867            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
868            description: i18n::I18nString::new(
869                "content.abilities.9f8e7d6c-5b4a-3c2d-1e0f-9a8b7c6d5e4f:description",
870            ),
871            description_values_script: Some("Result.push(7); Result.push(700)".to_string()),
872            vfx_object_path: "".into(),
873            cast_type: AbilityCastType::default(),
874            target_type: AbilityTargetType::default(),
875            range: 1,
876        },
877        AbilityTemplate {
878            id: uuid!("59e317c9-0108-4eb0-a41f-9d513b821542"),
879            is_fight_ui_visible: true,
880            fight_ui_visibility: AbilityFightUiVisibility::Class,
881            name: i18n::I18nString::new(
882                "content.abilities.59e317c9-0108-4eb0-a41f-9d513b821542:name",
883            ),
884            start_behavior: Some("attack_first_enemy".to_string()),
885            behavior: Some("ability_damage_target_5".to_string()),
886            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
887            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
888            cooldown: 10000000000000,
889            is_gacha_ability: false,
890            available_to_bots: true,
891            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
892            description: i18n::I18nString::new(
893                "content.abilities.59e317c9-0108-4eb0-a41f-9d513b821542:description",
894            ),
895            description_values_script: Some("Result.push(1); Result.push(100)".to_string()),
896            vfx_object_path: "".into(),
897            cast_type: AbilityCastType::default(),
898            target_type: AbilityTargetType::default(),
899            range: 1,
900        },
901        AbilityTemplate {
902            id: uuid!("c9c291ea-8a10-4bab-99df-ff0dc40e66f6"),
903            is_fight_ui_visible: true,
904            fight_ui_visibility: AbilityFightUiVisibility::Slotted,
905            name: i18n::I18nString::new(
906                "content.abilities.fd053ec6-8b23-4ba1-a31f-31b56d8c57bc:name",
907            ),
908            start_behavior: Some("attack_first_enemy".to_string()),
909            behavior: Some("ability_damage_target_5".to_string()),
910            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
911            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
912            cooldown: 0,
913            is_gacha_ability: true,
914            available_to_bots: true,
915            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
916            description: i18n::I18nString::new(
917                "content.abilities.fd053ec6-8b23-4ba1-a31f-31b56d8c57bc:description",
918            ),
919            description_values_script: None,
920            vfx_object_path: "".into(),
921            cast_type: AbilityCastType::default(),
922            target_type: AbilityTargetType::default(),
923            range: 1,
924        },
925        // BASIC_ABILITY referenced by the native `default_opponent_generation`
926        // (every generated bot is granted this ability) and by the bot class
927        // below. Id must match the `BASIC_ABILITY` const in
928        // `behaviors/opponent_generation.rs`. Hidden (non-slotted) basic.
929        AbilityTemplate {
930            id: uuid!("0194d64e-20f2-75e5-89c8-4cb812672485"),
931            is_fight_ui_visible: false,
932            fight_ui_visibility: AbilityFightUiVisibility::Hidden,
933            name: i18n::I18nString::new(
934                "content.abilities.da6c582b-7364-40bd-9b2d-946d8e20eaac:name",
935            ),
936            start_behavior: Some("attack_first_enemy".to_string()),
937            behavior: Some("ability_damage_target_5".to_string()),
938            icon_url: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
939            icon_path: "18789966-dfbb-445a-8ec1-c55397604203.webp".to_string(),
940            cooldown: 10000,
941            is_gacha_ability: false,
942            available_to_bots: true,
943            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
944            description: i18n::I18nString::new(
945                "content.abilities.da6c582b-7364-40bd-9b2d-946d8e20eaac:description",
946            ),
947            description_values_script: Some("Result.push(1); Result.push(100)".to_string()),
948            vfx_object_path: "".into(),
949            cast_type: AbilityCastType::default(),
950            target_type: AbilityTargetType::default(),
951            range: 1,
952        },
953    ]
954}
955
956fn generate_ability_cases_settings() -> NonEmptyVec<AbilityCasesSettingsByLevel> {
957    NonEmptyVec::new(vec![
958        AbilityCasesSettingsByLevel {
959            level: 1,
960            opens_to_upgrade: 0,
961            is_boundary_level: false,
962            rarity_weights: vec![
963                AbilityCaseRarityWeight {
964                    rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
965                    weight: PositiveF64::new(256.0),
966                },
967                AbilityCaseRarityWeight {
968                    rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
969                    weight: PositiveF64::new(128.0),
970                },
971                AbilityCaseRarityWeight {
972                    rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
973                    weight: PositiveF64::new(64.0),
974                },
975            ],
976            checkpoints: vec![AbilityCaseCheckpointReward {
977                required_opens: 1,
978                currency_rewards: vec![],
979                ability_rewards: vec![AbilityCaseCheckpointAbilityReward {
980                    amount: 1,
981                    min_rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
982                }],
983            }],
984            allowed_wishlist_rarity_ids: vec![
985                uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
986                uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
987            ],
988            evolve_rules: vec![AbilityCaseEvolveRule {
989                from_rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
990                small_roll_tries: 1,
991                big_roll_tries: 1,
992                to_rarity_weights: vec![AbilityCaseRarityWeight {
993                    rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
994                    weight: PositiveF64::new(1.0),
995                }],
996            }],
997            big_roll_currency_rewards: vec![],
998            big_roll_shards: vec![
999                BigRollShard {
1000                    min_rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1001                    count: 7,
1002                },
1003                BigRollShard {
1004                    min_rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1005                    count: 3,
1006                },
1007                BigRollShard {
1008                    min_rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1009                    count: 1,
1010                },
1011            ],
1012        },
1013        AbilityCasesSettingsByLevel {
1014            level: 2,
1015            opens_to_upgrade: 10,
1016            is_boundary_level: false,
1017            rarity_weights: vec![
1018                AbilityCaseRarityWeight {
1019                    rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1020                    weight: PositiveF64::new(256.0),
1021                },
1022                AbilityCaseRarityWeight {
1023                    rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1024                    weight: PositiveF64::new(128.0),
1025                },
1026                AbilityCaseRarityWeight {
1027                    rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1028                    weight: PositiveF64::new(64.0),
1029                },
1030            ],
1031            checkpoints: vec![],
1032            allowed_wishlist_rarity_ids: vec![uuid!("81b082cc-2736-4545-87d1-301f5de8951a")],
1033            evolve_rules: vec![],
1034            big_roll_currency_rewards: vec![],
1035            big_roll_shards: vec![
1036                BigRollShard {
1037                    min_rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1038                    count: 7,
1039                },
1040                BigRollShard {
1041                    min_rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1042                    count: 3,
1043                },
1044                BigRollShard {
1045                    min_rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1046                    count: 1,
1047                },
1048            ],
1049        },
1050        AbilityCasesSettingsByLevel {
1051            level: 3,
1052            opens_to_upgrade: 20,
1053            is_boundary_level: true,
1054            rarity_weights: vec![],
1055            checkpoints: vec![],
1056            allowed_wishlist_rarity_ids: vec![],
1057            evolve_rules: vec![],
1058            big_roll_currency_rewards: vec![],
1059            big_roll_shards: vec![],
1060        },
1061    ])
1062}
1063
1064fn generate_pet_rarities() -> Vec<PetRarity> {
1065    vec![
1066        PetRarity {
1067            id: uuid!("a0000000-0000-0000-0000-000000000001"),
1068            name: i18n::I18nString::Translated("Common Pet Rarity".to_string()),
1069            order: 1,
1070            color: "#ffffff".to_string(),
1071            bg_color: "#000000".to_string(),
1072            icon_path: "/pet_rarity_common.webp".to_string(),
1073            square_icon_path: "/pet_rarity_common.webp".to_string(),
1074        },
1075        PetRarity {
1076            id: uuid!("a0000000-0000-0000-0000-000000000002"),
1077            name: i18n::I18nString::Translated("Uncommon Pet Rarity".to_string()),
1078            order: 2,
1079            color: "#00ff00".to_string(),
1080            bg_color: "#003300".to_string(),
1081            icon_path: "/pet_rarity_uncommon.webp".to_string(),
1082            square_icon_path: "/pet_rarity_uncommon.webp".to_string(),
1083        },
1084    ]
1085}
1086
1087fn generate_pet_templates() -> Vec<PetTemplate> {
1088    vec![
1089        PetTemplate {
1090            id: uuid!("b0000000-0000-0000-0000-000000000001"),
1091            name: i18n::I18nString::Translated("Test Pet 1".to_string()),
1092            icon_path: "/pet1.webp".to_string(),
1093            spine_path: "/pet1_spine".to_string(),
1094            rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1095            stats: vec![
1096                PetSecondaryStat {
1097                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1098                    base_value: 100,
1099                    per_level_value: 10,
1100                },
1101                PetSecondaryStat {
1102                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1103                    base_value: 50,
1104                    per_level_value: 5,
1105                },
1106            ],
1107            active_ability_id: Some(uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac")),
1108            passive_ability_id: None,
1109            charge_rate_on_damage_dealt: 1000,
1110            charge_rate_on_damage_taken: 500,
1111            charge_rate_on_skill_use: 200,
1112            max_charge: 10000,
1113            is_gacha_pet: true,
1114        },
1115        PetTemplate {
1116            id: uuid!("b0000000-0000-0000-0000-000000000002"),
1117            name: i18n::I18nString::Translated("Test Pet 2".to_string()),
1118            icon_path: "/pet2.webp".to_string(),
1119            spine_path: "/pet2_spine".to_string(),
1120            rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1121            stats: vec![PetSecondaryStat {
1122                attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1123                base_value: 200,
1124                per_level_value: 20,
1125            }],
1126            active_ability_id: None,
1127            passive_ability_id: None,
1128            charge_rate_on_damage_dealt: 0,
1129            charge_rate_on_damage_taken: 0,
1130            charge_rate_on_skill_use: 0,
1131            max_charge: 0,
1132            is_gacha_pet: true,
1133        },
1134        PetTemplate {
1135            id: uuid!("b0000000-0000-0000-0000-000000000003"),
1136            name: i18n::I18nString::Translated("Test Pet 3 Uncommon".to_string()),
1137            icon_path: "/pet3.webp".to_string(),
1138            spine_path: "/pet3_spine".to_string(),
1139            rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1140            stats: vec![PetSecondaryStat {
1141                attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1142                base_value: 300,
1143                per_level_value: 30,
1144            }],
1145            active_ability_id: None,
1146            passive_ability_id: None,
1147            charge_rate_on_damage_dealt: 0,
1148            charge_rate_on_damage_taken: 0,
1149            charge_rate_on_skill_use: 0,
1150            max_charge: 0,
1151            is_gacha_pet: true,
1152        },
1153    ]
1154}
1155
1156fn generate_pet_levels() -> Vec<PetLevel> {
1157    vec![
1158        PetLevel {
1159            level: 2,
1160            rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1161            required_shards: 10,
1162        },
1163        PetLevel {
1164            level: 3,
1165            rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1166            required_shards: 20,
1167        },
1168        PetLevel {
1169            level: 2,
1170            rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1171            required_shards: 15,
1172        },
1173        PetLevel {
1174            level: 3,
1175            rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1176            required_shards: 30,
1177        },
1178    ]
1179}
1180
1181fn generate_pet_slots_levels() -> Vec<PetSlotsLevel> {
1182    vec![PetSlotsLevel {
1183        from_chapter_level: 1,
1184        pet_slots: 3,
1185    }]
1186}
1187
1188fn generate_pet_cases_settings() -> Vec<PetCasesSettingsByLevel> {
1189    // Pet rarity IDs from test config:
1190    // common   = a0000000-...-000000000001 (order 1, weight 256)
1191    // uncommon = a0000000-...-000000000002 (order 2, weight 128)
1192    vec![
1193        PetCasesSettingsByLevel {
1194            level: 1,
1195            opens_to_upgrade: 0,
1196            is_boundary_level: false,
1197            rarity_weights: vec![
1198                PetCaseRarityWeight {
1199                    rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1200                    weight: PositiveF64::new(256.0),
1201                },
1202                PetCaseRarityWeight {
1203                    rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1204                    weight: PositiveF64::new(128.0),
1205                },
1206            ],
1207            checkpoints: vec![PetCaseCheckpointReward {
1208                required_opens: 1,
1209                currency_rewards: vec![],
1210                pet_rewards: vec![PetCaseCheckpointPetReward {
1211                    amount: 1,
1212                    min_rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1213                }],
1214            }],
1215            allowed_wishlist_rarity_ids: vec![uuid!("a0000000-0000-0000-0000-000000000001")],
1216            big_roll_currency_rewards: vec![],
1217            big_roll_shards: vec![
1218                PetBigRollShard {
1219                    min_rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1220                    count: 8,
1221                },
1222                PetBigRollShard {
1223                    min_rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1224                    count: 3,
1225                },
1226            ],
1227        },
1228        PetCasesSettingsByLevel {
1229            level: 2,
1230            opens_to_upgrade: 10,
1231            is_boundary_level: false,
1232            rarity_weights: vec![
1233                PetCaseRarityWeight {
1234                    rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1235                    weight: PositiveF64::new(256.0),
1236                },
1237                PetCaseRarityWeight {
1238                    rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1239                    weight: PositiveF64::new(128.0),
1240                },
1241            ],
1242            checkpoints: vec![],
1243            allowed_wishlist_rarity_ids: vec![uuid!("a0000000-0000-0000-0000-000000000002")],
1244            big_roll_currency_rewards: vec![],
1245            big_roll_shards: vec![
1246                PetBigRollShard {
1247                    min_rarity_id: uuid!("a0000000-0000-0000-0000-000000000001"),
1248                    count: 8,
1249                },
1250                PetBigRollShard {
1251                    min_rarity_id: uuid!("a0000000-0000-0000-0000-000000000002"),
1252                    count: 3,
1253                },
1254            ],
1255        },
1256        PetCasesSettingsByLevel {
1257            level: 3,
1258            opens_to_upgrade: 20,
1259            is_boundary_level: true,
1260            rarity_weights: vec![],
1261            checkpoints: vec![],
1262            allowed_wishlist_rarity_ids: vec![],
1263            big_roll_currency_rewards: vec![],
1264            big_roll_shards: vec![],
1265        },
1266    ]
1267}
1268
1269fn generate_ability_rarities() -> Vec<AbilityRarity> {
1270    vec![
1271        AbilityRarity {
1272            id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1273            name: i18n::I18nString::new(
1274                "content.ability_rarities.33a0af72-2390-4df9-bd4f-f66b27ed7792:name",
1275            ),
1276            order: 1,
1277            color: "#97ca7a".to_string(),
1278            bg_color: "#244026".to_string(),
1279            icon_url: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1280            icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1281            square_icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1282            eff: 1.0,
1283        },
1284        AbilityRarity {
1285            id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1286            name: i18n::I18nString::new(
1287                "content.ability_rarities.6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e:name",
1288            ),
1289            order: 2,
1290            color: "#97ca7a".to_string(),
1291            bg_color: "#244026".to_string(),
1292            icon_url: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1293            icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1294            square_icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1295            eff: 1.0,
1296        },
1297        AbilityRarity {
1298            id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1299            name: i18n::I18nString::new(
1300                "content.ability_rarities.81b082cc-2736-4545-87d1-301f5de8951a:name",
1301            ),
1302            order: 3,
1303            color: "#97ca7a".to_string(),
1304            bg_color: "#244026".to_string(),
1305            icon_url: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1306            icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1307            square_icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1308            eff: 1.0,
1309        },
1310        AbilityRarity {
1311            id: uuid!("88ed32be-33cd-43a5-88e1-65c078e6372d"),
1312            name: i18n::I18nString::new(
1313                "content.ability_rarities.88ed32be-33cd-43a5-88e1-65c078e6372d:name",
1314            ),
1315            order: 4,
1316            color: "#97ca7a".to_string(),
1317            bg_color: "#244026".to_string(),
1318            icon_url: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1319            icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1320            square_icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
1321            eff: 1.0,
1322        },
1323    ]
1324}
1325
1326fn generate_ability_levels() -> Vec<AbilityLevel> {
1327    vec![
1328        AbilityLevel {
1329            level: 1,
1330            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1331            required_shards: 5,
1332        },
1333        AbilityLevel {
1334            level: 2,
1335            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1336            required_shards: 10,
1337        },
1338        AbilityLevel {
1339            level: 3,
1340            rarity_id: uuid!("33a0af72-2390-4df9-bd4f-f66b27ed7792"),
1341            required_shards: 10,
1342        },
1343        AbilityLevel {
1344            level: 1,
1345            rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1346            required_shards: 5,
1347        },
1348        AbilityLevel {
1349            level: 2,
1350            rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1351            required_shards: 10,
1352        },
1353        AbilityLevel {
1354            level: 3,
1355            rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1356            required_shards: 15,
1357        },
1358        AbilityLevel {
1359            level: 4,
1360            rarity_id: uuid!("6f0f1099-8ab1-4378-aea5-ac6bcbe6ec3e"),
1361            required_shards: 100,
1362        },
1363        AbilityLevel {
1364            level: 1,
1365            rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1366            required_shards: 5,
1367        },
1368        AbilityLevel {
1369            level: 2,
1370            rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1371            required_shards: 10,
1372        },
1373        AbilityLevel {
1374            level: 3,
1375            rarity_id: uuid!("81b082cc-2736-4545-87d1-301f5de8951a"),
1376            required_shards: 15,
1377        },
1378    ]
1379}
1380
1381fn generate_fight_settings() -> FightSettings {
1382    FightSettings {
1383        start_fight_delay_ticks_default: 2000,
1384        prepare_fight_win_delay_ticks_default: 1000,
1385        prepare_fight_lose_delay_ticks_default: 1000,
1386        end_fight_delay_ticks_default: 2000,
1387        player_start_position: Coordinates { x: 1, y: 1 },
1388        party_start_position: Coordinates { x: 1, y: 0 },
1389        pvp_enemy_start_position: Coordinates { x: 4, y: 1 },
1390    }
1391}
1392
1393fn generate_entities() -> Vec<EntityTemplate> {
1394    vec![
1395        EntityTemplate {
1396            id: uuid!("969f80ff-cf60-45e5-be6a-036911309ade"),
1397            name: "forest_goblin".into(),
1398            spine: "fe551450-4b55-4641-b376-a0184291fa05".into(),
1399            spine_skin_path: "Goblin:default".into(),
1400            spine_scale: 1,
1401            cast_time: 500,
1402            width: 1,
1403            ability_ids: vec![uuid!("50260b1c-7748-49bf-a1ed-34d69d029697")],
1404            attributes: vec![
1405                EntityAttribute {
1406                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1407                    value: 6,
1408                },
1409                EntityAttribute {
1410                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1411                    value: 5,
1412                },
1413                EntityAttribute {
1414                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1415                    value: 0,
1416                },
1417            ],
1418            rewards: vec![EnemyReward {
1419                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1420                from: 100,
1421                to: 100,
1422                drop_chance: 100.0,
1423            }],
1424            is_boss: false,
1425        },
1426        EntityTemplate {
1427            id: uuid!("bcc325dd-dc9a-4c30-b3c7-bfefdeec9a5f"),
1428            name: "shadow_wolf".into(),
1429            spine: "".into(),
1430            spine_skin_path: "Goblin:default".into(),
1431            spine_scale: 1,
1432            cast_time: 500,
1433            width: 1,
1434            ability_ids: vec![uuid!("50260b1c-7748-49bf-a1ed-34d69d029697")],
1435            attributes: vec![
1436                EntityAttribute {
1437                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1438                    value: 4,
1439                },
1440                EntityAttribute {
1441                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1442                    value: 8,
1443                },
1444                EntityAttribute {
1445                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1446                    value: 1,
1447                },
1448            ],
1449            rewards: vec![EnemyReward {
1450                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1451                from: 100,
1452                to: 100,
1453                drop_chance: 100.0,
1454            }],
1455            is_boss: false,
1456        },
1457        EntityTemplate {
1458            id: uuid!("94b110ce-a22c-461a-ab78-8a928ac1fad0"),
1459            name: "stone_giant".into(),
1460            spine: "".into(),
1461            spine_skin_path: "Goblin:default".into(),
1462            spine_scale: 1,
1463            cast_time: 500,
1464            width: 1,
1465            ability_ids: vec![uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a")],
1466            attributes: vec![
1467                EntityAttribute {
1468                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1469                    value: 10,
1470                },
1471                EntityAttribute {
1472                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1473                    value: 2,
1474                },
1475                EntityAttribute {
1476                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1477                    value: 5,
1478                },
1479            ],
1480            rewards: vec![EnemyReward {
1481                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1482                from: 100,
1483                to: 100,
1484                drop_chance: 100.0,
1485            }],
1486            is_boss: false,
1487        },
1488        EntityTemplate {
1489            id: uuid!("d414698e-afbd-4cd8-a594-901e8dcef231"),
1490            name: "fire_dragon".into(),
1491            spine: "".into(),
1492            spine_skin_path: "Goblin:default".into(),
1493            spine_scale: 1,
1494            cast_time: 500,
1495            width: 1,
1496            ability_ids: vec![
1497                uuid!("487a23e5-7401-4c34-a6c6-2401f95249cf"),
1498                uuid!("fd053ec6-8b23-4ba1-a31f-31b56d8c57bc"),
1499            ],
1500            attributes: vec![
1501                EntityAttribute {
1502                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1503                    value: 45,
1504                },
1505                EntityAttribute {
1506                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1507                    value: 4,
1508                },
1509                EntityAttribute {
1510                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1511                    value: 7,
1512                },
1513            ],
1514            rewards: vec![EnemyReward {
1515                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1516                from: 100,
1517                to: 100,
1518                drop_chance: 100.0,
1519            }],
1520            is_boss: false,
1521        },
1522        EntityTemplate {
1523            id: uuid!("447000b9-e155-4b74-82e3-df481ffc8136"),
1524            name: "phantom_assassin".into(),
1525            spine: "".into(),
1526            spine_skin_path: "Goblin:default".into(),
1527            spine_scale: 1,
1528            cast_time: 500,
1529            width: 1,
1530            ability_ids: vec![
1531                uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac"),
1532                uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a"),
1533                uuid!("50260b1c-7748-49bf-a1ed-34d69d029697"),
1534            ],
1535            attributes: vec![
1536                EntityAttribute {
1537                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1538                    value: 6,
1539                },
1540                EntityAttribute {
1541                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1542                    value: 10,
1543                },
1544                EntityAttribute {
1545                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1546                    value: 2,
1547                },
1548            ],
1549            rewards: vec![EnemyReward {
1550                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1551                from: 100,
1552                to: 100,
1553                drop_chance: 100.0,
1554            }],
1555            is_boss: false,
1556        },
1557        EntityTemplate {
1558            id: uuid!("0195e7d2-5ae7-70e4-88ec-b9417813b007"),
1559            name: "mini_roshan".into(),
1560            spine: "".into(),
1561            spine_skin_path: "Goblin:default".into(),
1562            spine_scale: 1,
1563            cast_time: 500,
1564            width: 1,
1565            ability_ids: vec![
1566                uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac"),
1567                uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a"),
1568            ],
1569            attributes: vec![
1570                EntityAttribute {
1571                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1572                    value: 150,
1573                },
1574                EntityAttribute {
1575                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1576                    value: 150,
1577                },
1578                EntityAttribute {
1579                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1580                    value: 150,
1581                },
1582            ],
1583            rewards: vec![EnemyReward {
1584                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1585                from: 500,
1586                to: 500,
1587                drop_chance: 100.0,
1588            }],
1589            is_boss: false,
1590        },
1591        EntityTemplate {
1592            id: uuid!("0195e7ce-ba97-7f6b-9ac6-0de3c160cde7"),
1593            name: "roshan".into(),
1594            spine: "".into(),
1595            spine_skin_path: "Goblin:default".into(),
1596            spine_scale: 1,
1597            cast_time: 500,
1598            width: 1,
1599            ability_ids: vec![
1600                uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac"),
1601                uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a"),
1602                uuid!("50260b1c-7748-49bf-a1ed-34d69d029697"),
1603            ],
1604            attributes: vec![
1605                EntityAttribute {
1606                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1607                    value: 300,
1608                },
1609                EntityAttribute {
1610                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1611                    value: 300,
1612                },
1613                EntityAttribute {
1614                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1615                    value: 300,
1616                },
1617            ],
1618            rewards: vec![EnemyReward {
1619                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1620                from: 1000,
1621                to: 1000,
1622                drop_chance: 100.0,
1623            }],
1624            is_boss: false,
1625        },
1626        EntityTemplate {
1627            id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
1628            name: "spawner".into(),
1629            spine: "".into(),
1630            spine_skin_path: "Goblin:default".into(),
1631            spine_scale: 1,
1632            cast_time: 500,
1633            width: 1,
1634            ability_ids: vec![],
1635            attributes: vec![
1636                EntityAttribute {
1637                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
1638                    value: 5,
1639                },
1640                EntityAttribute {
1641                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
1642                    value: 5,
1643                },
1644                EntityAttribute {
1645                    attribute_id: uuid!("42aea610-2ab7-41f7-95bf-5d6f00341ac9"),
1646                    value: 5,
1647                },
1648            ],
1649            rewards: vec![EnemyReward {
1650                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
1651                from: 1000,
1652                to: 1000,
1653                drop_chance: 100.0,
1654            }],
1655            is_boss: false,
1656        },
1657    ]
1658}
1659
1660fn generate_fight_templates() -> Vec<FightTemplate> {
1661    vec![
1662        FightTemplate {
1663            id: uuid!("360fc654-dea1-4f5d-97af-249ab30608ac"),
1664            title: i18n::I18nString::new(
1665                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1666            ),
1667            power: Some(300),
1668            fight_entities: vec![FightEntity {
1669                entity_type: EntityType::PVPEntity,
1670                position: Coordinates { x: 3, y: 1 },
1671                has_big_hp_bar: false,
1672                team: EntityTeam::Enemy,
1673            }],
1674            background: "".into(),
1675            max_duration_ticks: 300000,
1676            starting_fx: "".to_string(),
1677            fight_type: FightType::ArenaPVP,
1678            waves_amount: 1,
1679            prepare_fight_waves: None,
1680            start_behavior: Some("noop".to_string()),
1681            prepare_fight_win_duration_ticks: None,
1682            prepare_fight_lose_duration_ticks: None,
1683            start_fight_delay_ticks: None,
1684            end_fight_delay_ticks: None,
1685            bundle_reward_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
1686            stop_on_win: false,
1687            stop_on_lose: false,
1688            show_vs_screen: false,
1689            show_stages: None,
1690            target_width_cells: 6,
1691            is_dungeon: false,
1692            is_bossfight: false,
1693        },
1694        FightTemplate {
1695            id: uuid!("b92c69a2-6544-4b83-809f-5af290b75473"),
1696            title: i18n::I18nString::new(
1697                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1698            ),
1699            power: Some(300),
1700            fight_entities: vec![FightEntity {
1701                entity_type: EntityType::PVPEntity,
1702                position: Coordinates { x: 3, y: 1 },
1703                has_big_hp_bar: false,
1704                team: EntityTeam::Enemy,
1705            }],
1706            background: "".into(),
1707            max_duration_ticks: 300000,
1708            starting_fx: "".to_string(),
1709            fight_type: FightType::VassalPVP,
1710            waves_amount: 1,
1711            prepare_fight_waves: None,
1712            start_behavior: Some("noop".to_string()),
1713            prepare_fight_win_duration_ticks: None,
1714            prepare_fight_lose_duration_ticks: None,
1715            start_fight_delay_ticks: None,
1716            end_fight_delay_ticks: None,
1717            bundle_reward_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
1718            stop_on_win: false,
1719            stop_on_lose: false,
1720            show_vs_screen: false,
1721            show_stages: None,
1722            target_width_cells: 6,
1723            is_dungeon: false,
1724            is_bossfight: false,
1725        },
1726        FightTemplate {
1727            id: uuid!("b9d46e46-e8aa-4f73-9b67-694f567f1c48"),
1728            title: i18n::I18nString::new(
1729                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1730            ),
1731            power: Some(300),
1732            fight_entities: vec![
1733                FightEntity {
1734                    entity_type: EntityType::PVEEntity {
1735                        entity_template_id: uuid!("969f80ff-cf60-45e5-be6a-036911309ade"),
1736                    },
1737                    position: Coordinates { x: 3, y: 1 },
1738                    has_big_hp_bar: false,
1739                    team: EntityTeam::Enemy,
1740                },
1741                FightEntity {
1742                    entity_type: EntityType::PVEEntity {
1743                        entity_template_id: uuid!("969f80ff-cf60-45e5-be6a-036911309ade"),
1744                    },
1745                    position: Coordinates { x: 3, y: 2 },
1746                    has_big_hp_bar: false,
1747                    team: EntityTeam::Enemy,
1748                },
1749            ],
1750            background: "".into(),
1751            max_duration_ticks: 300000,
1752            starting_fx: "".to_string(),
1753            fight_type: FightType::CampaignFight,
1754            waves_amount: 1,
1755            prepare_fight_waves: None,
1756            start_behavior: Some("noop".to_string()),
1757            prepare_fight_win_duration_ticks: None,
1758            prepare_fight_lose_duration_ticks: None,
1759            start_fight_delay_ticks: None,
1760            end_fight_delay_ticks: None,
1761            bundle_reward_id: None,
1762            stop_on_win: false,
1763            stop_on_lose: false,
1764            show_vs_screen: false,
1765            show_stages: None,
1766            target_width_cells: 6,
1767            is_dungeon: false,
1768            is_bossfight: false,
1769        },
1770        FightTemplate {
1771            id: uuid!("44ca267b-7b6f-4508-ac74-a17b9dbeed99"),
1772            title: i18n::I18nString::new(
1773                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1774            ),
1775            power: Some(300),
1776            fight_entities: vec![FightEntity {
1777                entity_type: EntityType::PVEEntity {
1778                    entity_template_id: uuid!("bcc325dd-dc9a-4c30-b3c7-bfefdeec9a5f"),
1779                },
1780                position: Coordinates { x: 3, y: 1 },
1781                has_big_hp_bar: false,
1782                team: EntityTeam::Enemy,
1783            }],
1784            background: "".into(),
1785            max_duration_ticks: 300000,
1786            starting_fx: "".to_string(),
1787            fight_type: FightType::CampaignFight,
1788            waves_amount: 1,
1789            prepare_fight_waves: None,
1790            start_behavior: Some("noop".to_string()),
1791            prepare_fight_win_duration_ticks: None,
1792            prepare_fight_lose_duration_ticks: None,
1793            start_fight_delay_ticks: None,
1794            end_fight_delay_ticks: None,
1795            bundle_reward_id: None,
1796            stop_on_win: false,
1797            stop_on_lose: false,
1798            show_vs_screen: false,
1799            show_stages: None,
1800            target_width_cells: 6,
1801            is_dungeon: false,
1802            is_bossfight: false,
1803        },
1804        FightTemplate {
1805            id: uuid!("26f23346-541f-4a74-9ae0-efc3523b0ebf"),
1806            title: i18n::I18nString::new(
1807                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1808            ),
1809            power: Some(300),
1810            fight_entities: vec![
1811                FightEntity {
1812                    entity_type: EntityType::PVEEntity {
1813                        entity_template_id: uuid!("bcc325dd-dc9a-4c30-b3c7-bfefdeec9a5f"),
1814                    },
1815                    position: Coordinates { x: 2, y: 1 },
1816                    has_big_hp_bar: false,
1817                    team: EntityTeam::Enemy,
1818                },
1819                FightEntity {
1820                    entity_type: EntityType::PVEEntity {
1821                        entity_template_id: uuid!("94b110ce-a22c-461a-ab78-8a928ac1fad0"),
1822                    },
1823                    position: Coordinates { x: 2, y: 2 },
1824                    has_big_hp_bar: true,
1825                    team: EntityTeam::Enemy,
1826                },
1827            ],
1828            background: "".into(),
1829            max_duration_ticks: 300000,
1830            starting_fx: "".to_string(),
1831            fight_type: FightType::CampaignBossFight,
1832            waves_amount: 1,
1833            prepare_fight_waves: None,
1834            start_behavior: Some("noop".to_string()),
1835            prepare_fight_win_duration_ticks: None,
1836            prepare_fight_lose_duration_ticks: None,
1837            start_fight_delay_ticks: None,
1838            end_fight_delay_ticks: None,
1839            bundle_reward_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
1840            stop_on_win: false,
1841            stop_on_lose: false,
1842            show_vs_screen: false,
1843            show_stages: None,
1844            target_width_cells: 6,
1845            is_dungeon: false,
1846            is_bossfight: false,
1847        },
1848        FightTemplate {
1849            id: uuid!("f32d7a64-23b4-4d3f-bc31-801ae0f9acda"),
1850            title: i18n::I18nString::new(
1851                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1852            ),
1853            power: Some(300),
1854            fight_entities: vec![
1855                FightEntity {
1856                    entity_type: EntityType::PVEEntity {
1857                        entity_template_id: uuid!("969f80ff-cf60-45e5-be6a-036911309ade"),
1858                    },
1859                    position: Coordinates { x: 3, y: 1 },
1860                    has_big_hp_bar: false,
1861                    team: EntityTeam::Enemy,
1862                },
1863                FightEntity {
1864                    entity_type: EntityType::PVEEntity {
1865                        entity_template_id: uuid!("94b110ce-a22c-461a-ab78-8a928ac1fad0"),
1866                    },
1867                    position: Coordinates { x: 3, y: 2 },
1868                    has_big_hp_bar: false,
1869                    team: EntityTeam::Enemy,
1870                },
1871            ],
1872            background: "".into(),
1873            max_duration_ticks: 300000,
1874            starting_fx: "".to_string(),
1875            fight_type: FightType::CampaignFight,
1876            waves_amount: 1,
1877            prepare_fight_waves: None,
1878            start_behavior: Some("damage_first_entity_5".to_string()),
1879            prepare_fight_win_duration_ticks: None,
1880            prepare_fight_lose_duration_ticks: None,
1881            start_fight_delay_ticks: None,
1882            end_fight_delay_ticks: None,
1883            bundle_reward_id: None,
1884            stop_on_win: false,
1885            stop_on_lose: false,
1886            show_vs_screen: false,
1887            show_stages: None,
1888            target_width_cells: 6,
1889            is_dungeon: false,
1890            is_bossfight: false,
1891        },
1892        FightTemplate {
1893            id: uuid!("83f96aa7-1553-445f-b0d4-4bb1a13c68a1"),
1894            title: i18n::I18nString::new(
1895                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1896            ),
1897            power: Some(300),
1898            fight_entities: vec![
1899                FightEntity {
1900                    entity_type: EntityType::PVEEntity {
1901                        entity_template_id: uuid!("94b110ce-a22c-461a-ab78-8a928ac1fad0"),
1902                    },
1903                    position: Coordinates { x: 3, y: 1 },
1904                    has_big_hp_bar: false,
1905                    team: EntityTeam::Enemy,
1906                },
1907                FightEntity {
1908                    entity_type: EntityType::PVEEntity {
1909                        entity_template_id: uuid!("d414698e-afbd-4cd8-a594-901e8dcef231"),
1910                    },
1911                    position: Coordinates { x: 3, y: 2 },
1912                    has_big_hp_bar: false,
1913                    team: EntityTeam::Enemy,
1914                },
1915            ],
1916            background: "".into(),
1917            max_duration_ticks: 300000,
1918            starting_fx: "".to_string(),
1919            fight_type: FightType::CampaignFight,
1920            waves_amount: 1,
1921            prepare_fight_waves: None,
1922            start_behavior: Some("noop".to_string()),
1923            prepare_fight_win_duration_ticks: None,
1924            prepare_fight_lose_duration_ticks: None,
1925            start_fight_delay_ticks: None,
1926            end_fight_delay_ticks: None,
1927            bundle_reward_id: None,
1928            stop_on_win: false,
1929            stop_on_lose: false,
1930            show_vs_screen: false,
1931            show_stages: None,
1932            target_width_cells: 6,
1933            is_dungeon: false,
1934            is_bossfight: false,
1935        },
1936        FightTemplate {
1937            id: uuid!("a57fe553-3506-4211-a871-d199165a0f6a"),
1938            title: i18n::I18nString::new(
1939                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1940            ),
1941            power: Some(300),
1942            fight_entities: vec![
1943                FightEntity {
1944                    entity_type: EntityType::PVEEntity {
1945                        entity_template_id: uuid!("94b110ce-a22c-461a-ab78-8a928ac1fad0"),
1946                    },
1947                    position: Coordinates { x: 2, y: 1 },
1948                    has_big_hp_bar: false,
1949                    team: EntityTeam::Enemy,
1950                },
1951                FightEntity {
1952                    entity_type: EntityType::PVEEntity {
1953                        entity_template_id: uuid!("0195e7d2-5ae7-70e4-88ec-b9417813b007"),
1954                    },
1955                    position: Coordinates { x: 2, y: 2 },
1956                    has_big_hp_bar: true,
1957                    team: EntityTeam::Enemy,
1958                },
1959            ],
1960            background: "".into(),
1961            max_duration_ticks: 300000,
1962            starting_fx: "".to_string(),
1963            fight_type: FightType::CampaignBossFight,
1964            waves_amount: 1,
1965            prepare_fight_waves: None,
1966            start_behavior: Some("noop".to_string()),
1967            prepare_fight_win_duration_ticks: None,
1968            prepare_fight_lose_duration_ticks: None,
1969            start_fight_delay_ticks: None,
1970            end_fight_delay_ticks: None,
1971            bundle_reward_id: None,
1972            stop_on_win: false,
1973            stop_on_lose: false,
1974            show_vs_screen: false,
1975            show_stages: None,
1976            target_width_cells: 6,
1977            is_dungeon: false,
1978            is_bossfight: false,
1979        },
1980        FightTemplate {
1981            id: uuid!("c274b0bb-173e-49e3-9d36-2c32f1e2c8a1"),
1982            title: i18n::I18nString::new(
1983                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
1984            ),
1985            power: Some(300),
1986            fight_entities: vec![FightEntity {
1987                entity_type: EntityType::PVEEntity {
1988                    entity_template_id: uuid!("d414698e-afbd-4cd8-a594-901e8dcef231"),
1989                },
1990                position: Coordinates { x: 3, y: 1 },
1991                has_big_hp_bar: false,
1992                team: EntityTeam::Enemy,
1993            }],
1994            background: "".into(),
1995            max_duration_ticks: 300000,
1996            starting_fx: "".to_string(),
1997            fight_type: FightType::CampaignFight,
1998            waves_amount: 1,
1999            prepare_fight_waves: None,
2000            start_behavior: Some("noop".to_string()),
2001            prepare_fight_win_duration_ticks: None,
2002            prepare_fight_lose_duration_ticks: None,
2003            start_fight_delay_ticks: None,
2004            end_fight_delay_ticks: None,
2005            bundle_reward_id: None,
2006            stop_on_win: true,
2007            stop_on_lose: false,
2008            show_vs_screen: false,
2009            show_stages: None,
2010            target_width_cells: 6,
2011            is_dungeon: false,
2012            is_bossfight: false,
2013        },
2014        FightTemplate {
2015            id: uuid!("d02ac74e-5ad2-49c2-9a3e-927194c62adf"),
2016            title: i18n::I18nString::new(
2017                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2018            ),
2019            power: Some(300),
2020            fight_entities: vec![
2021                FightEntity {
2022                    entity_type: EntityType::PVEEntity {
2023                        entity_template_id: uuid!("969f80ff-cf60-45e5-be6a-036911309ade"),
2024                    },
2025                    position: Coordinates { x: 3, y: 1 },
2026                    has_big_hp_bar: false,
2027                    team: EntityTeam::Enemy,
2028                },
2029                FightEntity {
2030                    entity_type: EntityType::PVEEntity {
2031                        entity_template_id: uuid!("bcc325dd-dc9a-4c30-b3c7-bfefdeec9a5f"),
2032                    },
2033                    position: Coordinates { x: 3, y: 2 },
2034                    has_big_hp_bar: false,
2035                    team: EntityTeam::Enemy,
2036                },
2037                FightEntity {
2038                    entity_type: EntityType::PVEEntity {
2039                        entity_template_id: uuid!("d414698e-afbd-4cd8-a594-901e8dcef231"),
2040                    },
2041                    position: Coordinates { x: 4, y: 1 },
2042                    has_big_hp_bar: false,
2043                    team: EntityTeam::Enemy,
2044                },
2045            ],
2046            background: "".into(),
2047            max_duration_ticks: 300000,
2048            starting_fx: "".to_string(),
2049            fight_type: FightType::CampaignFight,
2050            waves_amount: 1,
2051            prepare_fight_waves: None,
2052            start_behavior: Some("noop".to_string()),
2053            prepare_fight_win_duration_ticks: None,
2054            prepare_fight_lose_duration_ticks: None,
2055            start_fight_delay_ticks: None,
2056            end_fight_delay_ticks: None,
2057            bundle_reward_id: None,
2058            stop_on_win: false,
2059            stop_on_lose: true,
2060            show_vs_screen: false,
2061            show_stages: None,
2062            target_width_cells: 6,
2063            is_dungeon: false,
2064            is_bossfight: false,
2065        },
2066        FightTemplate {
2067            id: uuid!("1f2b6501-d76f-4ed9-a6b6-7057c3ee16dc"),
2068            title: i18n::I18nString::new(
2069                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2070            ),
2071            power: Some(300),
2072            fight_entities: vec![
2073                FightEntity {
2074                    entity_type: EntityType::PVEEntity {
2075                        entity_template_id: uuid!("d414698e-afbd-4cd8-a594-901e8dcef231"),
2076                    },
2077                    position: Coordinates { x: 2, y: 1 },
2078                    has_big_hp_bar: false,
2079                    team: EntityTeam::Enemy,
2080                },
2081                FightEntity {
2082                    entity_type: EntityType::PVEEntity {
2083                        entity_template_id: uuid!("0195e7ce-ba97-7f6b-9ac6-0de3c160cde7"),
2084                    },
2085                    position: Coordinates { x: 2, y: 2 },
2086                    has_big_hp_bar: true,
2087                    team: EntityTeam::Enemy,
2088                },
2089            ],
2090            background: "".into(),
2091            max_duration_ticks: 300000,
2092            starting_fx: "".to_string(),
2093            fight_type: FightType::CampaignBossFight,
2094            waves_amount: 1,
2095            prepare_fight_waves: None,
2096            start_behavior: Some("noop".to_string()),
2097            prepare_fight_win_duration_ticks: None,
2098            prepare_fight_lose_duration_ticks: None,
2099            start_fight_delay_ticks: None,
2100            end_fight_delay_ticks: None,
2101            bundle_reward_id: None,
2102            stop_on_win: false,
2103            stop_on_lose: false,
2104            show_vs_screen: false,
2105            show_stages: None,
2106            target_width_cells: 6,
2107            is_dungeon: false,
2108            is_bossfight: false,
2109        },
2110        FightTemplate {
2111            id: uuid!("09207dc1-ef01-4222-8382-ee853770fc3d"),
2112            title: i18n::I18nString::new(
2113                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2114            ),
2115            power: Some(300),
2116            fight_entities: vec![
2117                FightEntity {
2118                    entity_type: EntityType::PVEEntity {
2119                        entity_template_id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
2120                    },
2121                    position: Coordinates { x: 2, y: 1 },
2122                    has_big_hp_bar: false,
2123                    team: EntityTeam::Enemy,
2124                },
2125                FightEntity {
2126                    entity_type: EntityType::PVEEntity {
2127                        entity_template_id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
2128                    },
2129                    position: Coordinates { x: 2, y: 2 },
2130                    has_big_hp_bar: true,
2131                    team: EntityTeam::Enemy,
2132                },
2133            ],
2134            background: "".into(),
2135            max_duration_ticks: 300000,
2136            starting_fx: "".to_string(),
2137            fight_type: FightType::CampaignBossFight,
2138            waves_amount: 1,
2139            prepare_fight_waves: None,
2140            start_behavior: Some("apply_spawn_on_death_to_player".to_string()),
2141            prepare_fight_win_duration_ticks: None,
2142            prepare_fight_lose_duration_ticks: None,
2143            start_fight_delay_ticks: None,
2144            end_fight_delay_ticks: None,
2145            bundle_reward_id: None,
2146            stop_on_win: false,
2147            stop_on_lose: false,
2148            show_vs_screen: false,
2149            show_stages: None,
2150            target_width_cells: 6,
2151            is_dungeon: false,
2152            is_bossfight: false,
2153        },
2154        FightTemplate {
2155            id: uuid!("669c9bac-7734-457a-8619-1c5b65802ac8"),
2156            title: i18n::I18nString::new(
2157                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2158            ),
2159            power: Some(300),
2160            fight_entities: vec![FightEntity {
2161                entity_type: EntityType::PVEEntity {
2162                    entity_template_id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
2163                },
2164                position: Coordinates { x: 2, y: 1 },
2165                has_big_hp_bar: false,
2166                team: EntityTeam::Enemy,
2167            }],
2168            background: "".into(),
2169            max_duration_ticks: 300000,
2170            starting_fx: "".to_string(),
2171            fight_type: FightType::CampaignBossFight,
2172            waves_amount: 3,
2173            // Typed mirror of the bespoke `prepare_fight_script` spawn above, plus
2174            // the per-wave spawns this 3-wave boss fight needs. The native
2175            // wave 0 spawns the extra enemy at prepare time; waves 1 and 2 each
2176            // spawn one enemy when the previous wave is cleared.
2177            prepare_fight_waves: Some(PrepareFightWaves {
2178                entities: vec![PrepareFightEntityPower {
2179                    entity_id: Some("0486f548-5040-4b70-b202-8b35a9880939".to_string()),
2180                    power: Some(1.0),
2181                }],
2182                waves: vec![
2183                    vec![PrepareFightSpawn {
2184                        entity_id: "0486f548-5040-4b70-b202-8b35a9880939".to_string(),
2185                        delay: Some(0.0),
2186                        position: Some(Coordinates { x: 3, y: 3 }),
2187                    }],
2188                    vec![PrepareFightSpawn {
2189                        entity_id: "0486f548-5040-4b70-b202-8b35a9880939".to_string(),
2190                        delay: Some(0.0),
2191                        position: Some(Coordinates { x: 3, y: 1 }),
2192                    }],
2193                    vec![PrepareFightSpawn {
2194                        entity_id: "0486f548-5040-4b70-b202-8b35a9880939".to_string(),
2195                        delay: Some(0.0),
2196                        position: Some(Coordinates { x: 3, y: 1 }),
2197                    }],
2198                ],
2199                time: 1.0,
2200                power: 100.0,
2201            }),
2202            start_behavior: Some("noop".to_string()),
2203            prepare_fight_win_duration_ticks: None,
2204            prepare_fight_lose_duration_ticks: None,
2205            start_fight_delay_ticks: None,
2206            end_fight_delay_ticks: None,
2207            bundle_reward_id: None,
2208            stop_on_win: false,
2209            stop_on_lose: false,
2210            show_vs_screen: false,
2211            show_stages: None,
2212            target_width_cells: 6,
2213            is_dungeon: false,
2214            is_bossfight: false,
2215        },
2216        FightTemplate {
2217            id: uuid!("bceb9758-a0e1-4f4c-90e9-f841e412baa2"),
2218            title: i18n::I18nString::new(
2219                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2220            ),
2221            power: Some(300),
2222            fight_entities: vec![FightEntity {
2223                entity_type: EntityType::PVEEntity {
2224                    entity_template_id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
2225                },
2226                position: Coordinates { x: 2, y: 1 },
2227                has_big_hp_bar: false,
2228                team: EntityTeam::Enemy,
2229            }],
2230            background: "".into(),
2231            max_duration_ticks: 300000,
2232            starting_fx: "".to_string(),
2233            fight_type: FightType::CampaignBossFight,
2234            waves_amount: 1,
2235            prepare_fight_waves: None,
2236            start_behavior: Some("noop".to_string()),
2237            prepare_fight_win_duration_ticks: Some(1),
2238            prepare_fight_lose_duration_ticks: Some(1),
2239            start_fight_delay_ticks: Some(1),
2240            end_fight_delay_ticks: Some(1),
2241            bundle_reward_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
2242            stop_on_win: false,
2243            stop_on_lose: false,
2244            show_vs_screen: false,
2245            show_stages: None,
2246            target_width_cells: 6,
2247            is_dungeon: false,
2248            is_bossfight: false,
2249        },
2250        FightTemplate {
2251            id: uuid!("3ba961a4-6eab-4251-a048-1edef27da219"),
2252            title: i18n::I18nString::new(
2253                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2254            ),
2255            power: Some(300),
2256            fight_entities: vec![FightEntity {
2257                entity_type: EntityType::PVEEntity {
2258                    entity_template_id: uuid!("0486f548-5040-4b70-b202-8b35a9880939"),
2259                },
2260                position: Coordinates { x: 2, y: 1 },
2261                has_big_hp_bar: false,
2262                team: EntityTeam::Enemy,
2263            }],
2264            background: "".into(),
2265            max_duration_ticks: 300000,
2266            starting_fx: "".to_string(),
2267            fight_type: FightType::CampaignBossFight,
2268            waves_amount: 2,
2269            prepare_fight_waves: None,
2270            start_behavior: Some("noop".to_string()),
2271            prepare_fight_win_duration_ticks: Some(1),
2272            prepare_fight_lose_duration_ticks: Some(1),
2273            start_fight_delay_ticks: Some(1),
2274            end_fight_delay_ticks: Some(1),
2275            bundle_reward_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
2276            stop_on_win: false,
2277            stop_on_lose: false,
2278            show_vs_screen: false,
2279            show_stages: None,
2280            target_width_cells: 6,
2281            is_dungeon: false,
2282            is_bossfight: false,
2283        },
2284    ]
2285}
2286
2287fn generate_dungeon_templates() -> Vec<DungeonTemplate> {
2288    vec![DungeonTemplate {
2289        id: uuid!("cfa28006-f242-47dc-9f69-e12587ea54fb"),
2290        title: i18n::I18nString::new("content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title"),
2291        description: i18n::I18nString::new(
2292            "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2293        ),
2294        key_currency_id: uuid!("85d98a50-510e-4853-b00a-84a51ad5cb50"),
2295        max_difficulty_level: 2,
2296        ui_background_path: "".to_string(),
2297        ui_banner_path: "".to_string(),
2298        tips: vec![
2299            DungeonTip {
2300                difficulty_level: 1,
2301                tip: i18n::I18nString::new(
2302                    "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2303                ),
2304            },
2305            DungeonTip {
2306                difficulty_level: 2,
2307                tip: i18n::I18nString::new(
2308                    "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2309                ),
2310            },
2311        ],
2312        fight_template_ids: vec![
2313            uuid!("bceb9758-a0e1-4f4c-90e9-f841e412baa2"),
2314            uuid!("bceb9758-a0e1-4f4c-90e9-f841e412baa2"),
2315        ],
2316        rewards_by_difficulty: vec![],
2317        main_reward: RewardType::Currency(uuid!("2ed77d25-cc1e-41ee-8f46-c4934ca8f684")),
2318        chapter_level_unlock: 2,
2319    }]
2320}
2321
2322fn generate_chapters() -> Vec<Chapter> {
2323    vec![
2324        Chapter {
2325            id: uuid!("9a51675f-9aa7-4f2b-9843-f2ce0cf8e6fd"),
2326            title: i18n::I18nString::new(
2327                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2328            ),
2329            level: 0,
2330            fight_ids: vec![
2331                uuid!("b9d46e46-e8aa-4f73-9b67-694f567f1c48"),
2332                uuid!("44ca267b-7b6f-4508-ac74-a17b9dbeed99"),
2333                uuid!("26f23346-541f-4a74-9ae0-efc3523b0ebf"),
2334            ],
2335        },
2336        Chapter {
2337            id: uuid!("a073ff29-425d-47d2-93e2-e254b5da3ec3"),
2338            title: i18n::I18nString::new(
2339                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2340            ),
2341            level: 1,
2342            fight_ids: vec![
2343                uuid!("f32d7a64-23b4-4d3f-bc31-801ae0f9acda"),
2344                uuid!("83f96aa7-1553-445f-b0d4-4bb1a13c68a1"),
2345                uuid!("a57fe553-3506-4211-a871-d199165a0f6a"),
2346            ],
2347        },
2348        Chapter {
2349            id: uuid!("35e6ccd4-7412-4910-ac1e-e6bdb6e1e1fb"),
2350            title: i18n::I18nString::new(
2351                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2352            ),
2353            level: 2,
2354            fight_ids: vec![
2355                uuid!("c274b0bb-173e-49e3-9d36-2c32f1e2c8a1"),
2356                uuid!("d02ac74e-5ad2-49c2-9a3e-927194c62adf"),
2357                uuid!("1f2b6501-d76f-4ed9-a6b6-7057c3ee16dc"),
2358            ],
2359        },
2360        Chapter {
2361            id: uuid!("fda76007-ff26-4a66-abef-0bd0f7ac3e60"),
2362            title: i18n::I18nString::new(
2363                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2364            ),
2365            level: 3,
2366            fight_ids: vec![uuid!("09207dc1-ef01-4222-8382-ee853770fc3d")],
2367        },
2368        Chapter {
2369            id: uuid!("e1c72dcf-017f-4d6b-8834-8e32f77c7534"),
2370            title: i18n::I18nString::new(
2371                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2372            ),
2373            level: 4,
2374            fight_ids: vec![uuid!("669c9bac-7734-457a-8619-1c5b65802ac8")],
2375        },
2376        Chapter {
2377            id: uuid!("de35b2ff-9330-4b1d-a268-5a82f7646936"),
2378            title: i18n::I18nString::new(
2379                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2380            ),
2381            level: 5,
2382            fight_ids: vec![uuid!("3ba961a4-6eab-4251-a048-1edef27da219")],
2383        },
2384    ]
2385}
2386
2387fn generate_character_levels() -> Vec<CharacterLevel> {
2388    let mut levels = vec![
2389        // Level 0 entry required by the native `balance::character_power`
2390        // (`character_level(0)` lookup) for bot/base-power computation.
2391        CharacterLevel {
2392            level: 0,
2393            ability_slots: 0,
2394            required_experience: 0,
2395            attributes: vec![EntityAttribute {
2396                attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
2397                value: 10,
2398            }],
2399        },
2400        CharacterLevel {
2401            level: 1,
2402            ability_slots: 0,
2403            required_experience: 0,
2404            attributes: vec![EntityAttribute {
2405                attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
2406                value: 10,
2407            }],
2408        },
2409        CharacterLevel {
2410            level: 2,
2411            ability_slots: 1,
2412            required_experience: 10000,
2413            attributes: vec![EntityAttribute {
2414                attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
2415                value: 30,
2416            }],
2417        },
2418    ];
2419    // Generated tail (levels 3..=500): the native PvP bot generator
2420    // (`default_opponent_generation` -> `level_by_day`) and the fight-prep
2421    // stats path (`calculate_player_entity_stats_with_zeroes`, which requires
2422    // an EXACT `character_level(level)` match) can pick high bot levels (e.g.
2423    // 72). The shipped config authors a full level table; the test fixture
2424    // mirrors that with a simple generated tail so any generated bot level
2425    // resolves. Levels 0..=2 above stay hand-authored (other tests assert on
2426    // their exact values).
2427    levels.extend((3..=500).map(|level| CharacterLevel {
2428        level,
2429        ability_slots: 1,
2430        required_experience: 10000 * level,
2431        // Flat low base attributes (matching level 2), so generated PvP bots —
2432        // whose stored level can be high (e.g. 72 for rating 1600 via
2433        // produced (its `character_power_calculate_script` was a trivial `1`).
2434        // Keeps arena fight outcomes calibrated to the existing assertions.
2435        attributes: vec![EntityAttribute {
2436            attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
2437            value: 30,
2438        }],
2439    }));
2440    levels
2441}
2442
2443fn generate_ability_slots_levels() -> Vec<AbilitySlotsLevel> {
2444    vec![
2445        AbilitySlotsLevel {
2446            from_chapter_level: 0,
2447            ability_slots: 2,
2448        },
2449        AbilitySlotsLevel {
2450            from_chapter_level: 2,
2451            ability_slots: 10,
2452        },
2453    ]
2454}
2455
2456fn generate_patron_levels() -> Vec<ReferralLevelInfo> {
2457    vec![
2458        ReferralLevelInfo {
2459            level: 1,
2460            required_experience: 0,
2461            lvlup_reward: vec![],
2462            daily_reward: vec![],
2463        },
2464        ReferralLevelInfo {
2465            level: 2,
2466            required_experience: 200,
2467            lvlup_reward: vec![CurrencyUnit {
2468                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2469                amount: 100,
2470            }],
2471            daily_reward: vec![CurrencyUnit {
2472                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2473                amount: 100,
2474            }],
2475        },
2476    ]
2477}
2478fn generate_quests() -> Vec<QuestTemplate> {
2479    vec![
2480        QuestTemplate {
2481            id: uuid!("e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5"),
2482            title: i18n::I18nString::new(
2483                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2484            ),
2485            description: i18n::I18nString::new(
2486                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2487            ),
2488            progress_behavior: Some("quest_event_level_1_then_2".to_string()),
2489            additional_quests_behavior: None,
2490            progress_target: 100,
2491            quest_group_type: QuestGroupType::Daily,
2492            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2493            progression_points: 70,
2494            starting: true,
2495            next_quest_ids: vec![],
2496            events_subscribe: vec!["NewCharacterLevel".to_string()],
2497            progress_if_inactive: false,
2498            screen_reference: None,
2499            code: None,
2500        },
2501        QuestTemplate {
2502            id: uuid!("4cf49879-8129-481c-b356-9e0f29335e84"),
2503            title: i18n::I18nString::new(
2504                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2505            ),
2506            description: i18n::I18nString::new(
2507                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2508            ),
2509            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2510            additional_quests_behavior: None,
2511            progress_target: 2,
2512            quest_group_type: QuestGroupType::Daily,
2513            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2514            progression_points: 70,
2515            starting: true,
2516            next_quest_ids: vec![],
2517            events_subscribe: vec!["PlayerNewItems".to_string()],
2518            progress_if_inactive: false,
2519            screen_reference: None,
2520            code: None,
2521        },
2522        QuestTemplate {
2523            id: uuid!("305300e2-f432-4cbf-ad46-85386a9a9410"),
2524            title: i18n::I18nString::new(
2525                "content.quests.305300e2-f432-4cbf-ad46-85386a9a9410:title",
2526            ),
2527            description: i18n::I18nString::new(
2528                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2529            ),
2530            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2531            additional_quests_behavior: Some("test_loop_task_1".to_string()),
2532            progress_target: 2,
2533            quest_group_type: QuestGroupType::LoopTask,
2534            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2535            progression_points: 80,
2536            starting: false,
2537            next_quest_ids: vec![uuid!("305300e2-f432-4cbf-ad46-85386a9a9410")],
2538            events_subscribe: vec!["PlayerNewItems".to_string()],
2539            progress_if_inactive: true,
2540            screen_reference: None,
2541            code: None,
2542        },
2543        QuestTemplate {
2544            id: uuid!("29540ca2-21f3-4f0e-a478-240adafed4e3"),
2545            title: i18n::I18nString::new(
2546                "content.quests.29540ca2-21f3-4f0e-a478-240adafed4e3:title",
2547            ),
2548            description: i18n::I18nString::new(
2549                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2550            ),
2551            progress_behavior: Some("increment_one".to_string()),
2552            additional_quests_behavior: Some("test_loop_task_2".to_string()),
2553            progress_target: 3,
2554            quest_group_type: QuestGroupType::LoopTask,
2555            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2556            progression_points: 100,
2557            starting: false,
2558            next_quest_ids: vec![uuid!("29540ca2-21f3-4f0e-a478-240adafed4e3")],
2559            events_subscribe: vec!["PlayerNewItems".to_string()],
2560            progress_if_inactive: false,
2561            screen_reference: None,
2562            code: None,
2563        },
2564        QuestTemplate {
2565            id: uuid!("9d3d2428-af3c-409f-a580-593de0fd06cf"),
2566            title: i18n::I18nString::new(
2567                "content.quests.29540ca2-21f3-4f0e-a478-240adafed4e3:title",
2568            ),
2569            description: i18n::I18nString::new(
2570                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2571            ),
2572            progress_behavior: Some("increment_one".to_string()),
2573            additional_quests_behavior: Some("test_loop_task_0".to_string()),
2574            progress_target: 5,
2575            quest_group_type: QuestGroupType::LoopTask,
2576            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2577            progression_points: 100,
2578            starting: false,
2579            next_quest_ids: vec![uuid!("9d3d2428-af3c-409f-a580-593de0fd06cf")],
2580            events_subscribe: vec!["PlayerNewItems".to_string()],
2581            progress_if_inactive: true,
2582            screen_reference: None,
2583            code: None,
2584        },
2585        QuestTemplate {
2586            id: uuid!("fa166167-f172-424f-b10b-a661fa8895db"),
2587            title: i18n::I18nString::new(
2588                "content.quests.fa166167-f172-424f-b10b-a661fa8895db:title",
2589            ),
2590            description: i18n::I18nString::new(
2591                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2592            ),
2593            progress_behavior: Some("quest_event_level_1_then_2".to_string()),
2594            additional_quests_behavior: None,
2595            progress_target: 2,
2596            quest_group_type: QuestGroupType::PatronLifetime,
2597            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2598            progression_points: 50,
2599            starting: true,
2600            next_quest_ids: vec![],
2601            events_subscribe: vec!["NewCharacterLevel".to_string()],
2602            progress_if_inactive: false,
2603            screen_reference: None,
2604            code: None,
2605        },
2606        QuestTemplate {
2607            id: uuid!("2cf76eea-5b4b-4258-9051-3d3188845c5e"),
2608            title: i18n::I18nString::new(
2609                "content.quests.fa166167-f172-424f-b10b-a661fa8895db:title",
2610            ),
2611            description: i18n::I18nString::new(
2612                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2613            ),
2614            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2615            additional_quests_behavior: None,
2616            progress_target: 2,
2617            quest_group_type: QuestGroupType::PatronLifetime,
2618            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2619            progression_points: 50,
2620            starting: true,
2621            next_quest_ids: vec![],
2622            events_subscribe: vec!["PlayerNewItems".to_string()],
2623            progress_if_inactive: false,
2624            screen_reference: None,
2625            code: None,
2626        },
2627        QuestTemplate {
2628            id: uuid!("78552c1c-5e8a-4f95-8f48-a5671051852e"),
2629            title: i18n::I18nString::new(
2630                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2631            ),
2632            description: i18n::I18nString::new(
2633                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2634            ),
2635            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2636            additional_quests_behavior: None,
2637            progress_target: 2,
2638            quest_group_type: QuestGroupType::PatronDaily,
2639            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2640            progression_points: 1000,
2641            starting: true,
2642            next_quest_ids: vec![],
2643            events_subscribe: vec!["PlayerNewItems".to_string()],
2644            progress_if_inactive: false,
2645            screen_reference: None,
2646            code: None,
2647        },
2648        QuestTemplate {
2649            id: uuid!("b16fea6d-6b9b-484c-b25b-8bec70234691"),
2650            title: i18n::I18nString::new(
2651                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2652            ),
2653            description: i18n::I18nString::new(
2654                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2655            ),
2656            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2657            additional_quests_behavior: None,
2658            progress_target: 2,
2659            quest_group_type: QuestGroupType::Hidden,
2660            bundle_id: None,
2661            progression_points: 0,
2662            starting: true,
2663            next_quest_ids: vec![uuid!("ce92f997-e41e-4cfe-9963-e100cc121289")],
2664            events_subscribe: vec!["PlayerNewItems".to_string()],
2665            progress_if_inactive: false,
2666            screen_reference: None,
2667            code: None,
2668        },
2669        QuestTemplate {
2670            id: uuid!("ce92f997-e41e-4cfe-9963-e100cc121289"),
2671            title: i18n::I18nString::new(
2672                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2673            ),
2674            description: i18n::I18nString::new(
2675                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2676            ),
2677            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2678            additional_quests_behavior: None,
2679            progress_target: 2,
2680            quest_group_type: QuestGroupType::Hidden,
2681            bundle_id: None,
2682            progression_points: 0,
2683            starting: false,
2684            next_quest_ids: vec![uuid!("db3c73c6-e300-42dd-be47-3f820ab8b095")],
2685            events_subscribe: vec!["PlayerNewItems".to_string()],
2686            progress_if_inactive: false,
2687            screen_reference: None,
2688            code: None,
2689        },
2690        QuestTemplate {
2691            id: uuid!("c3ae0d0c-a0c3-49f4-b538-fd19f388d0b2"),
2692            title: i18n::I18nString::new(
2693                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2694            ),
2695            description: i18n::I18nString::new(
2696                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2697            ),
2698            progress_behavior: Some("increment_one".to_string()),
2699            additional_quests_behavior: Some("test_loop_task_seed".to_string()),
2700            progress_target: 1,
2701            quest_group_type: QuestGroupType::Hidden,
2702            bundle_id: None,
2703            progression_points: 0,
2704            starting: true,
2705            next_quest_ids: vec![],
2706            events_subscribe: vec!["PlayerNewItems".to_string()],
2707            progress_if_inactive: false,
2708            screen_reference: None,
2709            code: None,
2710        },
2711        QuestTemplate {
2712            id: uuid!("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"),
2713            title: i18n::I18nString::new(
2714                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2715            ),
2716            description: i18n::I18nString::new(
2717                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2718            ),
2719            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2720            additional_quests_behavior: None,
2721            progress_target: 2,
2722            quest_group_type: QuestGroupType::Hidden,
2723            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2724            progression_points: 0,
2725            starting: false,
2726            next_quest_ids: vec![],
2727            events_subscribe: vec!["NewCharacterLevel".to_string()],
2728            progress_if_inactive: false,
2729            screen_reference: None,
2730            code: None,
2731        },
2732        QuestTemplate {
2733            id: uuid!("db3c73c6-e300-42dd-be47-3f820ab8b095"),
2734            title: i18n::I18nString::new(
2735                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2736            ),
2737            description: i18n::I18nString::new(
2738                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2739            ),
2740            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2741            additional_quests_behavior: None,
2742            progress_target: 2,
2743            quest_group_type: QuestGroupType::Lifetime,
2744            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2745            progression_points: 0,
2746            starting: false,
2747            next_quest_ids: vec![],
2748            events_subscribe: vec!["PlayerNewItems".to_string()],
2749            progress_if_inactive: false,
2750            screen_reference: None,
2751            code: None,
2752        },
2753        QuestTemplate {
2754            id: uuid!("d1986660-eb69-4051-a256-dbb1d8e5377f"),
2755            title: i18n::I18nString::new(
2756                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2757            ),
2758            description: i18n::I18nString::new(
2759                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2760            ),
2761            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2762            additional_quests_behavior: None,
2763            progress_target: 2,
2764            quest_group_type: QuestGroupType::Lifetime,
2765            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2766            progression_points: 0,
2767            starting: true,
2768            next_quest_ids: vec![],
2769            events_subscribe: vec!["PlayerNewItems".to_string()],
2770            progress_if_inactive: false,
2771            screen_reference: None,
2772            code: None,
2773        },
2774        // ========== Achievement quests (independent, all starting, no chaining) ==========
2775        // Achievement 1: "Sell 2 items"
2776        QuestTemplate {
2777            id: uuid!("a1000000-0000-0000-0000-000000000001"),
2778            title: i18n::I18nString::new(
2779                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2780            ),
2781            description: i18n::I18nString::new(
2782                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2783            ),
2784            progress_behavior: Some("quest_current_0_then_1_else_2".to_string()),
2785            additional_quests_behavior: None,
2786            progress_target: 2,
2787            quest_group_type: QuestGroupType::Achievement,
2788            progression_points: 50,
2789            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2790            starting: true,
2791            next_quest_ids: vec![],
2792            events_subscribe: vec!["PlayerNewItems".to_string()],
2793            progress_if_inactive: false,
2794            screen_reference: None,
2795            code: None,
2796        },
2797        // Achievement 2: "Sell 3 items"
2798        QuestTemplate {
2799            id: uuid!("a1000000-0000-0000-0000-000000000002"),
2800            title: i18n::I18nString::new(
2801                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2802            ),
2803            description: i18n::I18nString::new(
2804                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2805            ),
2806            progress_behavior: Some("increment_one".to_string()),
2807            additional_quests_behavior: None,
2808            progress_target: 3,
2809            quest_group_type: QuestGroupType::Achievement,
2810            progression_points: 50,
2811            bundle_id: Some(uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82")),
2812            starting: true,
2813            next_quest_ids: vec![],
2814            events_subscribe: vec!["PlayerNewItems".to_string()],
2815            progress_if_inactive: false,
2816            screen_reference: None,
2817            code: None,
2818        },
2819        // ========== Progress Pass quests (starting: false — rows are pre-seeded
2820        // in test_progress_pass.rs via storage::quests::update_current_progress) ==========
2821        QuestTemplate {
2822            id: uuid!("aa000000-0000-0000-0000-000000000001"),
2823            title: i18n::I18nString::new(
2824                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2825            ),
2826            description: i18n::I18nString::new(
2827                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2828            ),
2829            progress_behavior: Some("increment_one".to_string()),
2830            additional_quests_behavior: None,
2831            progress_target: 1,
2832            quest_group_type: QuestGroupType::ProgressPass,
2833            progression_points: 0,
2834            bundle_id: None,
2835            starting: false,
2836            next_quest_ids: vec![],
2837            events_subscribe: vec!["PlayerNewItems".to_string()],
2838            progress_if_inactive: false,
2839            screen_reference: None,
2840            code: None,
2841        },
2842        QuestTemplate {
2843            id: uuid!("bb000000-0000-0000-0000-000000000002"),
2844            title: i18n::I18nString::new(
2845                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2846            ),
2847            description: i18n::I18nString::new(
2848                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2849            ),
2850            progress_behavior: Some("increment_one".to_string()),
2851            additional_quests_behavior: None,
2852            progress_target: 2,
2853            quest_group_type: QuestGroupType::ProgressPass,
2854            progression_points: 0,
2855            bundle_id: None,
2856            starting: false,
2857            next_quest_ids: vec![],
2858            events_subscribe: vec!["PlayerNewItems".to_string()],
2859            progress_if_inactive: false,
2860            screen_reference: None,
2861            code: None,
2862        },
2863        QuestTemplate {
2864            id: uuid!("cc000000-0000-0000-0000-000000000003"),
2865            title: i18n::I18nString::new(
2866                "content.quests.e3bc23d8-2035-44d0-b8c1-bb1996ac6bc5:title",
2867            ),
2868            description: i18n::I18nString::new(
2869                "content.quests.78552c1c-5e8a-4f95-8f48-a5671051852e:title",
2870            ),
2871            progress_behavior: Some("increment_one".to_string()),
2872            additional_quests_behavior: None,
2873            progress_target: 1,
2874            quest_group_type: QuestGroupType::ProgressPass,
2875            progression_points: 0,
2876            bundle_id: None,
2877            starting: false,
2878            next_quest_ids: vec![],
2879            events_subscribe: vec!["PlayerNewItems".to_string()],
2880            progress_if_inactive: false,
2881            screen_reference: None,
2882            code: None,
2883        },
2884    ]
2885}
2886
2887fn generate_quests_progression_settings() -> QuestsProgressionSettings {
2888    let point = |points: u64, amount: i64| QuestsProgressionPointSettings {
2889        points,
2890        reward: vec![CurrencyUnit {
2891            currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2892            amount,
2893        }],
2894    };
2895    QuestsProgressionSettings {
2896        daily: vec![point(35, 10), point(70, 70), point(100, 100)],
2897        weekly: vec![point(30, 100), point(60, 500), point(100, 1000)],
2898        achievement: vec![point(50, 10), point(100, 50), point(200, 100)],
2899    }
2900}
2901
2902fn generate_vassals_settings() -> VassalsSettings {
2903    VassalsSettings {
2904        vassal_shield_duration_secs: 0,
2905        // Ports of the test fixture's `vassal_reward_script` /
2906        // `suzerain_reward_script` (both push CurrencyUnit(b59b33a2, 42)).
2907        suzerain_reward_fn: "test_vassal_link_reward_42".to_string(),
2908        vassal_reward_fn: "test_vassal_link_reward_42".to_string(),
2909    }
2910}
2911
2912fn generate_pvp_settings() -> PvpSettings {
2913    PvpSettings {
2914        max_matchmaking_opponents_count: 10,
2915        matchmaking_character_level_data: 2,
2916    }
2917}
2918
2919fn generate_vassal_tasks() -> Vec<VassalTaskTemplate> {
2920    vec![
2921        VassalTaskTemplate {
2922            id: uuid!("7b4a7bf5-01e0-4078-9cc1-52b742ed2b1e"),
2923            title: i18n::I18nString::new(
2924                "content.vassal_tasks.7b4a7bf5-01e0-4078-9cc1-52b742ed2b1e:title",
2925            ),
2926            duration_sec: 2,
2927            // Ports of the fixture's `if GoodTask {42} else {32}` scripts.
2928            reward_fn: "test_vassal_task_reward_42_32".to_string(),
2929            loyalty_fn: "test_vassal_task_loyalty_42_32".to_string(),
2930        },
2931        VassalTaskTemplate {
2932            id: uuid!("05e915bf-55fe-4419-bcf0-5f90833f17bd"),
2933            title: i18n::I18nString::new(
2934                "content.vassal_tasks.05e915bf-55fe-4419-bcf0-5f90833f17bd:title",
2935            ),
2936            duration_sec: 10,
2937            // Ports of the fixture's `if GoodTask {0} else {42}` scripts.
2938            reward_fn: "test_vassal_task_reward_0_42".to_string(),
2939            loyalty_fn: "test_vassal_task_loyalty_0_42".to_string(),
2940        },
2941    ]
2942}
2943
2944fn generate_gifts() -> Vec<GiftTemplate> {
2945    vec![
2946        GiftTemplate {
2947            id: uuid!("5e4b493e-78d2-45cd-931a-3d12ff669038"),
2948            gift_type: GiftType::VassalGift,
2949            price: vec![CurrencyUnit {
2950                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2951                amount: 50,
2952            }],
2953            reward: vec![CurrencyUnit {
2954                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2955                amount: 50,
2956            }],
2957            loyalty: 50,
2958        },
2959        GiftTemplate {
2960            id: uuid!("64e8ead6-44cf-4798-a18d-db648d598930"),
2961            gift_type: GiftType::GenericGift,
2962            price: vec![CurrencyUnit {
2963                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2964                amount: 50,
2965            }],
2966            reward: vec![CurrencyUnit {
2967                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2968                amount: 50,
2969            }],
2970            loyalty: 0,
2971        },
2972    ]
2973}
2974
2975fn generate_currencies() -> Vec<Currency> {
2976    vec![
2977        Currency {
2978            id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
2979            name: i18n::I18nString::new(
2980                "content.currencies.b59b33a2-4d19-4e2c-9cea-e03ea15882a0:name",
2981            ),
2982            description: i18n::I18nString::new(
2983                "content.currencies.b59b33a2-4d19-4e2c-9cea-e03ea15882a0:name",
2984            ),
2985            icon_url: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
2986            icon_path: "e0bcf4ea-b2b5-47d6-9d76-985797a5a818.webp".to_string(),
2987        },
2988        Currency {
2989            id: uuid!("22297520-abb8-45b9-9fbb-c418b8001246"),
2990            name: i18n::I18nString::new(
2991                "content.currencies.22297520-abb8-45b9-9fbb-c418b8001246:name",
2992            ),
2993            description: i18n::I18nString::new(
2994                "content.currencies.22297520-abb8-45b9-9fbb-c418b8001246:name",
2995            ),
2996            icon_url: "b2446d1a-368d-4747-8b92-82a279bc6193.webp".to_string(),
2997            icon_path: "b2446d1a-368d-4747-8b92-82a279bc6193.webp".to_string(),
2998        },
2999        Currency {
3000            id: uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
3001            name: i18n::I18nString::new(
3002                "content.currencies.6c050b07-5282-4a23-8bbf-dabecd27cade:name",
3003            ),
3004            description: i18n::I18nString::new(
3005                "content.currencies.6c050b07-5282-4a23-8bbf-dabecd27cade:name",
3006            ),
3007            icon_url: "50a5cd4b-6b68-4e44-b4dd-9acb928bfea5.webp".to_string(),
3008            icon_path: "50a5cd4b-6b68-4e44-b4dd-9acb928bfea5.webp".to_string(),
3009        },
3010    ]
3011}
3012
3013fn generate_mail_templates() -> Vec<MailTemplate> {
3014    vec![
3015        MailTemplate {
3016            id: uuid!("f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1"),
3017            title: i18n::I18nString::new(
3018                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3019            ),
3020            message: i18n::I18nString::new(
3021                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3022            ),
3023            bundle_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
3024            lifetime_secs: 86_400,
3025            send_type: MailSendType {
3026                scheduled_at: None,
3027                repeat: None,
3028            },
3029            restrictions: None,
3030            is_auto_send: true,
3031        },
3032        MailTemplate {
3033            id: uuid!("7216d615-6adc-46ab-b5af-4d8e26f38baf"),
3034            title: i18n::I18nString::new(
3035                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3036            ),
3037            message: i18n::I18nString::new(
3038                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3039            ),
3040            bundle_id: None,
3041            lifetime_secs: 86_400,
3042            send_type: MailSendType {
3043                scheduled_at: None,
3044                repeat: None,
3045            },
3046            restrictions: None,
3047            is_auto_send: true,
3048        },
3049        MailTemplate {
3050            id: uuid!("5dd4c42f-95af-4f10-8fa7-7f567686e756"),
3051            title: i18n::I18nString::new(
3052                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3053            ),
3054            message: i18n::I18nString::new(
3055                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3056            ),
3057            bundle_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
3058            lifetime_secs: 86_400,
3059            send_type: MailSendType {
3060                scheduled_at: Some("2015-01-01-00-00-00".to_string()),
3061                repeat: Some(MailRepeatType::Daily),
3062            },
3063            restrictions: None,
3064            is_auto_send: true,
3065        },
3066        MailTemplate {
3067            id: uuid!("7b1d8c15-74c5-44d1-b7fb-bb027d5389c6"),
3068            title: i18n::I18nString::new(
3069                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3070            ),
3071            message: i18n::I18nString::new(
3072                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3073            ),
3074            bundle_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
3075            lifetime_secs: 86_400,
3076            send_type: MailSendType {
3077                scheduled_at: Some("2015-01-01-00-00-00".to_string()),
3078                repeat: Some(MailRepeatType::Daily),
3079            },
3080            restrictions: None,
3081            is_auto_send: false,
3082        },
3083        MailTemplate {
3084            id: uuid!("98eea253-ac84-49ea-becb-4d5ef9c18b5c"),
3085            title: i18n::I18nString::new(
3086                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3087            ),
3088            message: i18n::I18nString::new(
3089                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3090            ),
3091            bundle_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
3092            lifetime_secs: 86_400,
3093            send_type: MailSendType {
3094                scheduled_at: Some("2015-01-01-00-00-00".to_string()),
3095                repeat: Some(MailRepeatType::Daily),
3096            },
3097            restrictions: None,
3098            is_auto_send: false,
3099        },
3100        MailTemplate {
3101            id: uuid!("0042b76d-bfbe-4e02-a6a6-4881e229da88"),
3102            title: i18n::I18nString::new(
3103                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:title",
3104            ),
3105            message: i18n::I18nString::new(
3106                "content.mails.f3d6c5a1-2b4e-4c9a-9f61-8d2e9af2a1b1:message",
3107            ),
3108            bundle_id: Some(uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d")),
3109            lifetime_secs: 86_400,
3110            send_type: MailSendType {
3111                scheduled_at: Some("2015-01-01-00-00-00".to_string()),
3112                repeat: Some(MailRepeatType::Daily),
3113            },
3114            restrictions: None,
3115            is_auto_send: false,
3116        },
3117    ]
3118}
3119
3120fn generate_inventory_levels() -> Vec<InventoryLevel> {
3121    vec![InventoryLevel {
3122        from_chapter_level: 0,
3123        item_types: all::<ItemType>().collect(),
3124    }]
3125}
3126
3127fn generate_arena_settings() -> ArenaSettings {
3128    ArenaSettings {
3129        base_rating: 1000,
3130        // `win_rating_increase_const` (+10) / `lose_rating_increase_const` (-5)
3131        // are authoritative. Kept in sync with the native consts to avoid
3132        // misleading future readers.
3133        matches_history_size: 5,
3134        leaderboard_size: 5,
3135        arena_tickets_currency_id: uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
3136        matchmaking_character_rating_delta: 30,
3137        pvp_cooldown_secs: 60,
3138        win_reward_bundle_id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
3139        lose_reward_bundle_id: uuid!("e18fc101-6615-440c-9a1d-42f509986ccc"),
3140        arena_ticket_buy_currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3141        arena_ticket_price: CurrencyUnit {
3142            currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3143            amount: 100,
3144        },
3145        arena_matches_ttl_days: 30,
3146        rematch_max_rating_increase: 250,
3147        rematch_max_rating_decrease: -100,
3148    }
3149}
3150
3151fn generate_arena_leagues() -> Vec<ArenaLeague> {
3152    vec![
3153        ArenaLeague {
3154            id: uuid!("842ce55f-c6b9-4d2f-b86b-6288529a8658"),
3155            name: i18n::I18nString::new(
3156                "content.arena.leagues.842ce55f-c6b9-4d2f-b86b-6288529a8658:name",
3157            ),
3158            min_rating: 0,
3159            max_rating: 999,
3160        },
3161        ArenaLeague {
3162            id: uuid!("d1936748-b14e-4a7a-b17d-aaf2d70e5077"),
3163            name: i18n::I18nString::new(
3164                "content.arena.leagues.d1936748-b14e-4a7a-b17d-aaf2d70e5077:name",
3165            ),
3166            min_rating: 1000,
3167            max_rating: 1999,
3168        },
3169        ArenaLeague {
3170            id: uuid!("1e69174c-5628-4a65-ba87-55ac6e31868f"),
3171            name: i18n::I18nString::new(
3172                "content.arena.leagues.1e69174c-5628-4a65-ba87-55ac6e31868f:name",
3173            ),
3174            min_rating: 2000,
3175            max_rating: 10000,
3176        },
3177    ]
3178}
3179
3180fn generate_matchmaking_settings() -> MatchmakingSettings {
3181    MatchmakingSettings {
3182        opponent_positions: vec![
3183            OpponentPositionSettings {
3184                min_rating_diff_percent: 15.0,
3185                max_rating_diff_percent: 20.0,
3186                max_rating_for_bots: 1000,
3187                bot_power_multiplier: 1.0,
3188            },
3189            OpponentPositionSettings {
3190                min_rating_diff_percent: -7.0,
3191                max_rating_diff_percent: 7.0,
3192                max_rating_for_bots: 1000,
3193                bot_power_multiplier: 1.0,
3194            },
3195            OpponentPositionSettings {
3196                min_rating_diff_percent: -7.0,
3197                max_rating_diff_percent: 7.0,
3198                max_rating_for_bots: 1000,
3199                bot_power_multiplier: 1.0,
3200            },
3201            OpponentPositionSettings {
3202                min_rating_diff_percent: -17.0,
3203                max_rating_diff_percent: -15.0,
3204                max_rating_for_bots: 1000,
3205                bot_power_multiplier: 1.0,
3206            },
3207        ],
3208        percentile_threshold: 30.0,
3209    }
3210}
3211
3212fn generate_event_descriptions() -> Vec<EventDescription> {
3213    vec![EventDescription {
3214        name: "NewCharacterLevel".to_string(),
3215        description: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3216        color: "#008000".to_string(),
3217        icon_url: "tmp".to_string(),
3218        bg_url: "tmp".to_string(),
3219        bg_path: "tmp".to_string(),
3220        text_url: "tmp".to_string(),
3221        effect_url: "tmp".to_string(),
3222        ttl_milliseconds: 2000,
3223    }]
3224}
3225
3226fn generate_classes() -> Vec<class::Class> {
3227    vec![
3228        class::Class {
3229            id: uuid!("00000000-0000-0000-0000-000000000000"),
3230            character_asset: "2f7d1e2e-0e33-4730-a3b6-de7122ed9044".to_string(),
3231            spine: "".into(),
3232            cast_time: 500,
3233            basic_abilities: vec![uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac")],
3234            starter_bundle_id: None,
3235            attributes: vec![],
3236            ability_rarity_id: uuid!("88ed32be-33cd-43a5-88e1-65c078e6372d"),
3237            tier: class::ClassTier::C,
3238            background_image_path: "".to_string(),
3239            icon_path: "".to_string(),
3240            description: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3241            name: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3242            demo_skins: vec![],
3243            weapon_type: i18n::I18nString::Translated("".into()),
3244            class_abilities: vec![],
3245            main_attribute: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
3246            main_attribute_optimal_value: 0,
3247            default_weapon_skin_id: uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2"),
3248        },
3249        class::Class {
3250            id: uuid!("5956e37c-ca7f-45cf-8bfb-49601dc9aca3"),
3251            character_asset: "2f7d1e2e-0e33-4730-a3b6-de7122ed9044".to_string(),
3252            spine: "".into(),
3253            cast_time: 500,
3254            basic_abilities: vec![uuid!("da6c582b-7364-40bd-9b2d-946d8e20eaac")],
3255            starter_bundle_id: Some(uuid!("c86eed27-03d0-4c06-a6b2-e8688c09f7ed")),
3256            attributes: vec![
3257                class::ClassAttribute::EntityAttribute(EntityAttribute {
3258                    attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
3259                    value: 50,
3260                }),
3261                class::ClassAttribute::EntityAttribute(EntityAttribute {
3262                    attribute_id: uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6"),
3263                    value: 20,
3264                }),
3265            ],
3266            ability_rarity_id: uuid!("88ed32be-33cd-43a5-88e1-65c078e6372d"),
3267            tier: class::ClassTier::A,
3268            background_image_path: "".to_string(),
3269            icon_path: "".to_string(),
3270            description: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3271            name: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3272            demo_skins: vec![],
3273            weapon_type: i18n::I18nString::Translated("".into()),
3274            class_abilities: vec![],
3275            main_attribute: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
3276            main_attribute_optimal_value: 0,
3277            default_weapon_skin_id: uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2"),
3278        },
3279        class::Class {
3280            id: uuid!("95d314ee-ce2c-4b10-a8bc-596b0f03ab8a"),
3281            character_asset: "2f7d1e2e-0e33-4730-a3b6-de7122ed9044".to_string(),
3282            spine: "".into(),
3283            cast_time: 500,
3284            basic_abilities: vec![
3285                uuid!("59e317c9-0108-4eb0-a41f-9d513b821542"),
3286                uuid!("41ee5532-a293-4f88-bfb6-5ffca1e57acc"),
3287            ],
3288            starter_bundle_id: None,
3289            attributes: vec![],
3290            ability_rarity_id: uuid!("88ed32be-33cd-43a5-88e1-65c078e6372d"),
3291            tier: class::ClassTier::A,
3292            background_image_path: "".to_string(),
3293            icon_path: "".to_string(),
3294            description: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3295            name: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3296            demo_skins: vec![],
3297            weapon_type: i18n::I18nString::Translated("".into()),
3298            class_abilities: vec![],
3299            main_attribute: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
3300            main_attribute_optimal_value: 0,
3301            default_weapon_skin_id: uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2"),
3302        },
3303        // BOT_CLASS assigned to generated PvP bots by the native
3304        // `default_opponent_generation` (`set_class_id`). Id must match the
3305        // `BOT_CLASS` const in `behaviors/opponent_generation.rs`.
3306        class::Class {
3307            id: uuid!("0195c7de-144f-7b53-b370-468e9ae8f744"),
3308            character_asset: "2f7d1e2e-0e33-4730-a3b6-de7122ed9044".to_string(),
3309            spine: "".into(),
3310            cast_time: 500,
3311            basic_abilities: vec![uuid!("0194d64e-20f2-75e5-89c8-4cb812672485")],
3312            starter_bundle_id: None,
3313            attributes: vec![],
3314            ability_rarity_id: uuid!("88ed32be-33cd-43a5-88e1-65c078e6372d"),
3315            tier: class::ClassTier::C,
3316            background_image_path: "".to_string(),
3317            icon_path: "".to_string(),
3318            description: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3319            name: i18n::I18nString::new("content.event.newcharacterlevel:name"),
3320            demo_skins: vec![],
3321            weapon_type: i18n::I18nString::Translated("".into()),
3322            class_abilities: vec![],
3323            main_attribute: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
3324            main_attribute_optimal_value: 0,
3325            default_weapon_skin_id: uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2"),
3326        },
3327    ]
3328}
3329
3330fn generate_projectiles() -> Vec<Projectile> {
3331    vec![Projectile {
3332        id: uuid!("1ca53a04-5321-4d93-bdc4-55caed5ab83b"),
3333        start_behavior: Some("projectile_fixed_500_damage_300".to_string()),
3334        behavior: Some("projectile_damage_target_5".to_string()),
3335        vfx: "".to_string(),
3336    }]
3337}
3338
3339fn generate_basic_items() -> Vec<ItemTemplate> {
3340    vec![
3341        ItemTemplate {
3342            id: uuid!("176c4cc5-7b93-43b4-9f90-958e2791a8d6"),
3343            name: i18n::I18nString::new("content.items.176c4cc5-7b93-43b4-9f90-958e2791a8d6:name"),
3344            icon_url: "/leather_boots.png".to_string(),
3345            icon_path: "/leather_boots.png".to_string(),
3346            item_type: ItemType::Weapon,
3347            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3348            attributes_settings: ItemAttributeSettings {
3349                optional_attributes_count: 0,
3350                optional_attributes_ids: vec![],
3351            },
3352            skin_id: Some(uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2")),
3353            exclude_from_mimic: false,
3354            required_class: None,
3355            fixed_power: None,
3356            next_mimic_item_code: None,
3357        },
3358        ItemTemplate {
3359            id: uuid!("9f86cff5-2ce6-4191-95cf-2271cc3686f5"),
3360            name: i18n::I18nString::new("content.items.9f86cff5-2ce6-4191-95cf-2271cc3686f5:name"),
3361            icon_url: "/iron_chestplate.png".to_string(),
3362            icon_path: "/iron_chestplate.png".to_string(),
3363            item_type: ItemType::Torso,
3364            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3365            attributes_settings: ItemAttributeSettings {
3366                optional_attributes_count: 0,
3367                optional_attributes_ids: vec![],
3368            },
3369            skin_id: Some(uuid!("a1b2c3d4-e5f6-7890-abcd-ef1234567890")),
3370            exclude_from_mimic: false,
3371            required_class: None,
3372            fixed_power: None,
3373            next_mimic_item_code: None,
3374        },
3375        ItemTemplate {
3376            id: uuid!("6779d933-1663-4d02-8e47-2bf8ce06aeee"),
3377            name: i18n::I18nString::new("content.items.6779d933-1663-4d02-8e47-2bf8ce06aeee:name"),
3378            icon_url: "/mask_of_fury.png".to_string(),
3379            icon_path: "/mask_of_fury.png".to_string(),
3380            item_type: ItemType::Head,
3381            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3382            attributes_settings: ItemAttributeSettings {
3383                optional_attributes_count: 0,
3384                optional_attributes_ids: vec![],
3385            },
3386            skin_id: None,
3387            exclude_from_mimic: false,
3388            required_class: None,
3389            fixed_power: None,
3390            next_mimic_item_code: None,
3391        },
3392        ItemTemplate {
3393            id: uuid!("a1b2c3d4-e5f6-7890-abcd-ef1234567891"),
3394            name: i18n::I18nString::new("content.items.a1b2c3d4-e5f6-7890-abcd-ef1234567891:name"),
3395            icon_url: "/simple_sword.png".to_string(),
3396            icon_path: "/simple_sword.png".to_string(),
3397            item_type: ItemType::Weapon,
3398            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3399            attributes_settings: ItemAttributeSettings {
3400                optional_attributes_count: 0,
3401                optional_attributes_ids: vec![],
3402            },
3403            skin_id: None,
3404            exclude_from_mimic: false,
3405            required_class: None,
3406            fixed_power: None,
3407            next_mimic_item_code: None,
3408        },
3409        ItemTemplate {
3410            id: uuid!("37108f62-1595-4e2d-8d51-708b96311511"),
3411            name: i18n::I18nString::new("content.items.37108f62-1595-4e2d-8d51-708b96311511:name"),
3412            icon_url: "/gloves_of_agility.png".to_string(),
3413            icon_path: "/gloves_of_agility.png".to_string(),
3414            item_type: ItemType::Legs,
3415            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3416            attributes_settings: ItemAttributeSettings {
3417                optional_attributes_count: 1,
3418                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3419            },
3420            skin_id: None,
3421            exclude_from_mimic: false,
3422            required_class: None,
3423            fixed_power: None,
3424            next_mimic_item_code: None,
3425        },
3426        ItemTemplate {
3427            id: uuid!("edee37e9-cfea-4406-b16e-64f5f3aed7c2"),
3428            name: i18n::I18nString::new("content.items.edee37e9-cfea-4406-b16e-64f5f3aed7c2:name"),
3429            icon_url: "/wizard_hat.png".to_string(),
3430            icon_path: "/wizard_hat.png".to_string(),
3431            item_type: ItemType::Shoulders,
3432            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3433            attributes_settings: ItemAttributeSettings {
3434                optional_attributes_count: 1,
3435                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3436            },
3437            skin_id: None,
3438            exclude_from_mimic: false,
3439            required_class: None,
3440            fixed_power: None,
3441            next_mimic_item_code: None,
3442        },
3443        ItemTemplate {
3444            id: uuid!("88ee0a22-b495-40bd-ad1b-132998a1cd37"),
3445            name: i18n::I18nString::new("content.items.88ee0a22-b495-40bd-ad1b-132998a1cd37:name"),
3446            icon_url: "/mystic_pants.png".to_string(),
3447            icon_path: "/mystic_pants.png".to_string(),
3448            item_type: ItemType::Boots,
3449            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3450            attributes_settings: ItemAttributeSettings {
3451                optional_attributes_count: 1,
3452                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3453            },
3454            skin_id: None,
3455            exclude_from_mimic: false,
3456            required_class: None,
3457            fixed_power: None,
3458            next_mimic_item_code: None,
3459        },
3460        ItemTemplate {
3461            id: uuid!("1eda3aa8-8868-4f77-8ac3-cb2c0b080f1d"),
3462            name: i18n::I18nString::new("content.items.1eda3aa8-8868-4f77-8ac3-cb2c0b080f1d:name"),
3463            icon_url: "/immortal_blade.png".to_string(),
3464            icon_path: "/immortal_blade.png".to_string(),
3465            item_type: ItemType::Gloves,
3466            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3467            attributes_settings: ItemAttributeSettings {
3468                optional_attributes_count: 1,
3469                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3470            },
3471            skin_id: None,
3472            exclude_from_mimic: false,
3473            required_class: None,
3474            fixed_power: None,
3475            next_mimic_item_code: None,
3476        },
3477        ItemTemplate {
3478            id: uuid!("255ad949-72cc-48dc-8129-30584a5a69b7"),
3479            name: i18n::I18nString::new("content.items.255ad949-72cc-48dc-8129-30584a5a69b7:name"),
3480            icon_url: "/divine_armor.png".to_string(),
3481            icon_path: "/divine_armor.png".to_string(),
3482            item_type: ItemType::Waist,
3483            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3484            attributes_settings: ItemAttributeSettings {
3485                optional_attributes_count: 1,
3486                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3487            },
3488            skin_id: None,
3489            exclude_from_mimic: false,
3490            required_class: None,
3491            fixed_power: None,
3492            next_mimic_item_code: None,
3493        },
3494        ItemTemplate {
3495            id: uuid!("32be4f79-5327-4118-9594-e67a3a97959d"),
3496            name: i18n::I18nString::new("content.items.32be4f79-5327-4118-9594-e67a3a97959d:name"),
3497            icon_url: "/ancient_crown.png".to_string(),
3498            icon_path: "/ancient_crown.png".to_string(),
3499            item_type: ItemType::Neck,
3500            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3501            attributes_settings: ItemAttributeSettings {
3502                optional_attributes_count: 1,
3503                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3504            },
3505            skin_id: None,
3506            exclude_from_mimic: false,
3507            required_class: None,
3508            fixed_power: None,
3509            next_mimic_item_code: None,
3510        },
3511        ItemTemplate {
3512            id: uuid!("8c7cdde1-e80b-4b40-a5d8-039bf39db419"),
3513            name: i18n::I18nString::new("content.items.8c7cdde1-e80b-4b40-a5d8-039bf39db419:name"),
3514            icon_url: "/godlike_scepter.png".to_string(),
3515            icon_path: "/godlike_scepter.png".to_string(),
3516            item_type: ItemType::Ring,
3517            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3518            attributes_settings: ItemAttributeSettings {
3519                optional_attributes_count: 1,
3520                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3521            },
3522            skin_id: None,
3523            exclude_from_mimic: false,
3524            required_class: None,
3525            fixed_power: None,
3526            next_mimic_item_code: None,
3527        },
3528        // Artifact template exists so `test_open_item_case_never_drops_artifact`
3529        // is a real guard: without the chest-drop exclusion filter, a chest could
3530        // roll this template and the test would fail. Artifacts are granted via
3531        // bundles, never chests.
3532        ItemTemplate {
3533            id: uuid!("019efa51-cd2d-7589-b8db-8f5630201743"),
3534            name: i18n::I18nString::Translated("Test Artifact".to_string()),
3535            icon_url: "/test_artifact.png".to_string(),
3536            icon_path: "/test_artifact.png".to_string(),
3537            item_type: ItemType::Artifact,
3538            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3539            attributes_settings: ItemAttributeSettings {
3540                optional_attributes_count: 1,
3541                optional_attributes_ids: vec![uuid!("3a6ec1c8-7494-43df-a345-d23e297b892d")],
3542            },
3543            skin_id: None,
3544            exclude_from_mimic: false,
3545            required_class: None,
3546            fixed_power: None,
3547            next_mimic_item_code: None,
3548        },
3549    ]
3550}
3551
3552fn generate_items(item_rarities: &[ItemRarity]) -> Vec<ItemTemplate> {
3553    let basic_items = generate_basic_items();
3554    let mut result = basic_items.clone();
3555    for rarity in &item_rarities[1..] {
3556        for item in &basic_items {
3557            result.push(ItemTemplate {
3558                id: Uuid::now_v7(),
3559                rarity_id: rarity.id,
3560                ..item.clone()
3561            });
3562        }
3563    }
3564    result
3565}
3566
3567fn generate_bundles() -> Vec<bundles::BundleRaw> {
3568    let soft = uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0");
3569    let hard = uuid!("22297520-abb8-45b9-9fbb-c418b8001246");
3570    let unit = |currency_id: Uuid, amount: i64| CurrencyUnit {
3571        currency_id,
3572        amount,
3573    };
3574    let ability_1 = uuid!("7e584338-057d-41a2-a80e-8e2c76e98f6a");
3575    let ability_2 = uuid!("487a23e5-7401-4c34-a6c6-2401f95249cf");
3576    let shard = |ability_id: Uuid, amount: i64| bundles::BundleShardAmount { ability_id, amount };
3577    let test_item_id = uuid!("176c4cc5-7b93-43b4-9f90-958e2791a8d6");
3578    let empty_step = |item_type: bundles::BundleStepType| bundles::BundleRawStep {
3579        item_type,
3580        currencies: vec![],
3581        currency_branch: None,
3582        behavior: None,
3583        shards: vec![],
3584        item_template_ids: vec![],
3585        item_ttl_seconds: None,
3586        has_pop_up: false,
3587    };
3588
3589    let first_steps = vec![
3590        bundles::BundleRawStep {
3591            currencies: vec![unit(soft, 80), unit(hard, 70)],
3592            has_pop_up: true,
3593            ..empty_step(bundles::BundleStepType::Currency)
3594        },
3595        bundles::BundleRawStep {
3596            shards: vec![shard(ability_1, 11), shard(ability_2, 1)],
3597            has_pop_up: true,
3598            ..empty_step(bundles::BundleStepType::Ability)
3599        },
3600        bundles::BundleRawStep {
3601            item_template_ids: vec![test_item_id],
3602            ..empty_step(bundles::BundleStepType::Item)
3603        },
3604    ];
3605
3606    let second_steps = vec![
3607        bundles::BundleRawStep {
3608            currencies: vec![unit(soft, 50), unit(hard, 170)],
3609            has_pop_up: true,
3610            ..empty_step(bundles::BundleStepType::Currency)
3611        },
3612        bundles::BundleRawStep {
3613            shards: vec![shard(ability_1, 6), shard(ability_2, 18)],
3614            has_pop_up: true,
3615            ..empty_step(bundles::BundleStepType::Ability)
3616        },
3617        // (`f86cff5-2ce6-4191-95cf-2271cc3686f5`, 7 hex in the first group).
3618        // No test asserts a second-bundle item reward (`test_multiple_bundles`
3619        // only walks the currency + ability steps), so this step grants nothing.
3620        empty_step(bundles::BundleStepType::Item),
3621    ];
3622
3623    let fourth_steps = vec![
3624        bundles::BundleRawStep {
3625            behavior: Some("test_afk_currency_step0".to_string()),
3626            has_pop_up: true,
3627            ..empty_step(bundles::BundleStepType::Currency)
3628        },
3629        empty_step(bundles::BundleStepType::Ability),
3630        empty_step(bundles::BundleStepType::Item),
3631    ];
3632
3633    let all_at_once_steps = vec![
3634        bundles::BundleRawStep {
3635            currencies: vec![unit(soft, 100), unit(hard, 200)],
3636            has_pop_up: true,
3637            ..empty_step(bundles::BundleStepType::Currency)
3638        },
3639        bundles::BundleRawStep {
3640            shards: vec![shard(ability_1, 25), shard(ability_2, 10)],
3641            ..empty_step(bundles::BundleStepType::Ability)
3642        },
3643        bundles::BundleRawStep {
3644            item_template_ids: vec![test_item_id],
3645            ..empty_step(bundles::BundleStepType::Item)
3646        },
3647    ];
3648
3649    let basic_bundle = vec![bundles::BundleRawStep {
3650        currencies: vec![unit(soft, 100)],
3651        has_pop_up: true,
3652        ..empty_step(bundles::BundleStepType::Currency)
3653    }];
3654
3655    let basic_bundle_no_popup = vec![bundles::BundleRawStep {
3656        currencies: vec![unit(soft, 100)],
3657        ..empty_step(bundles::BundleStepType::Currency)
3658    }];
3659
3660    vec![
3661        bundles::BundleRaw {
3662            id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
3663            steps: first_steps,
3664            claim_mode: bundles::BundleClaimMode::Sequential,
3665        },
3666        bundles::BundleRaw {
3667            id: uuid!("e18fc101-6615-440c-9a1d-42f509986ccc"),
3668            steps: second_steps,
3669            claim_mode: bundles::BundleClaimMode::Sequential,
3670        },
3671        bundles::BundleRaw {
3672            id: uuid!("c86eed27-03d0-4c06-a6b2-e8688c09f7ed"),
3673            steps: vec![],
3674            claim_mode: bundles::BundleClaimMode::Sequential,
3675        },
3676        bundles::BundleRaw {
3677            id: uuid!("1ed77d25-cc1e-41ee-8f46-c4934ca8f684"),
3678            steps: fourth_steps,
3679            claim_mode: bundles::BundleClaimMode::Sequential,
3680        },
3681        bundles::BundleRaw {
3682            id: uuid!("a7f3b8e2-9c4d-4a5e-b6f1-d8e9c7a2b1f0"),
3683            steps: all_at_once_steps,
3684            claim_mode: bundles::BundleClaimMode::AllAtOnce,
3685        },
3686        bundles::BundleRaw {
3687            id: uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8"),
3688            steps: basic_bundle,
3689            claim_mode: bundles::BundleClaimMode::AllAtOnce,
3690        },
3691        bundles::BundleRaw {
3692            id: uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82"),
3693            steps: basic_bundle_no_popup,
3694            claim_mode: bundles::BundleClaimMode::AllAtOnce,
3695        },
3696    ]
3697}
3698
3699fn generate_ability_presets_settings() -> ability_presets::AbilityPresetsSettings {
3700    ability_presets::AbilityPresetsSettings {
3701        max_presets_count: 4,
3702        default_preset_name: i18n::I18nString::new("content.ability_presets.default_preseset:name"),
3703    }
3704}
3705
3706fn generate_bots_settings() -> BotsSettings {
3707    BotsSettings {
3708        username_generation_settings: UsernameGenerationSettings {
3709            prefixes: vec!["Angry".to_string(), "Chubby".to_string()],
3710            suffixes: vec!["Lord".to_string(), "Queen".to_string()],
3711            template: "{prefix}{suffix} [bot]".to_string(),
3712        },
3713        photo_generation_settings: PhotoGenerationSettings {
3714            templates: vec!["img1".to_string(), "img2".to_string()],
3715        },
3716    }
3717}
3718
3719fn generate_reports_settings() -> ReportsSettings {
3720    ReportsSettings {
3721        ticket_categories: vec!["Technical support".to_string(), "Bug".to_string()],
3722        bug_categories: vec!["Bug".to_string()],
3723    }
3724}
3725
3726fn generate_afk_rewards_levels() -> Vec<AfkRewardsByLevel> {
3727    vec![AfkRewardsByLevel {
3728        chapter_level: 0,
3729        currency_rates: vec![CurrencyRate {
3730            currency_id: uuid!("2ed77d25-cc1e-41ee-8f46-c4934ca8f684"),
3731            rate_per_minute: PositiveF64::new(10.0),
3732        }],
3733        bonus_weights: NonEmptyVec::new(vec![
3734            AfkRewardBonusWeight {
3735                bonus_type: AfkRewardBonusType::Currency(uuid!(
3736                    "2ed77d25-cc1e-41ee-8f46-c4934ca8f684"
3737                )),
3738                weight: PositiveF64::new(1.0),
3739                count: PositiveI64::new(100),
3740            },
3741            AfkRewardBonusWeight {
3742                bonus_type: AfkRewardBonusType::Ability(uuid!(
3743                    "3ed77d25-cc1e-41ee-8f46-c4934ca8f684"
3744                )),
3745                weight: PositiveF64::new(0.5),
3746                count: PositiveI64::new(1),
3747            },
3748            AfkRewardBonusWeight {
3749                bonus_type: AfkRewardBonusType::Item(uuid!("4ed77d25-cc1e-41ee-8f46-c4934ca8f684")),
3750                weight: PositiveF64::new(0.5),
3751                count: PositiveI64::new(1),
3752            },
3753        ]),
3754    }]
3755}
3756
3757fn generate_afk_rewards_settings() -> AfkRewardsSettings {
3758    AfkRewardsSettings {
3759        bundle_id: uuid!("1ed77d25-cc1e-41ee-8f46-c4934ca8f684"),
3760        min_required_time_sec: 4,
3761        max_possible_time_sec: 8,
3762        bonus_calculation_rate_sec: NonZeroU64::new(60),
3763        instant_reward_duration_sec: 6,
3764        instant_reward_gems_prices: vec![50, 100, 150],
3765        afk_instant_ad_daily_limit: 2,
3766    }
3767}
3768
3769fn generate_users_generating_settings() -> UsersGeneratingSettings {
3770    UsersGeneratingSettings {
3771        username_generation_settings: UsernameGenerationSettings {
3772            prefixes: vec!["Big".to_string(), "Small".to_string()],
3773            suffixes: vec!["Egor".to_string(), "Danya".to_string()],
3774            template: "{prefix} {suffix}".to_string(),
3775        },
3776        photo_generation_settings: PhotoGenerationSettings {
3777            templates: vec!["img1".to_string(), "img2".to_string()],
3778        },
3779    }
3780}
3781
3782fn generate_skins() -> Vec<ConfigSkin> {
3783    vec![
3784        ConfigSkin {
3785            id: uuid!("59a4dd34-b395-436f-8f81-2fb36ee1b714"),
3786            name: i18n::I18nString::new("content.skins.59a4dd34-b395-436f-8f81-2fb36ee1b714:name"),
3787            unlock_description: Some(i18n::I18nString::Translated("Default face unlock".into())),
3788            code: "default_face".to_string(),
3789            skin_type: SkinType::Face,
3790            icon_url: "/skins/face_default.webp".to_string(),
3791            icon_path: "/skins/face_default.webp".to_string(),
3792            spine_path: "".to_string(),
3793            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3794            price: None,
3795            color: Some("".into()),
3796        },
3797        ConfigSkin {
3798            id: uuid!("44d8fbed-9ec9-4a57-865a-59d32465a1f2"),
3799            name: i18n::I18nString::new("content.skins.44d8fbed-9ec9-4a57-865a-59d32465a1f2:name"),
3800            unlock_description: Some(i18n::I18nString::Translated(
3801                "Default hairstyle unlock".into(),
3802            )),
3803            code: "default_hairstyle".to_string(),
3804            skin_type: SkinType::Hairstyle,
3805            icon_url: "/skins/hair_default.webp".to_string(),
3806            icon_path: "/skins/face_default.webp".to_string(),
3807            spine_path: "".to_string(),
3808            rarity_id: uuid!("272f3e73-6b3e-43a0-88d6-d34bdaf5aeae"),
3809            price: Some(vec![CurrencyUnit {
3810                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3811                amount: 100,
3812            }]),
3813            color: Some("".into()),
3814        },
3815        ConfigSkin {
3816            id: uuid!("a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
3817            name: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3818            unlock_description: Some(i18n::I18nString::Translated("Test armor unlock".into())),
3819            code: "test_armor".to_string(),
3820            skin_type: SkinType::Armor,
3821            icon_url: "/skins/armor_test.webp".to_string(),
3822            icon_path: "/skins/face_default.webp".to_string(),
3823            spine_path: "".to_string(),
3824            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3825            price: None,
3826            color: Some("".into()),
3827        },
3828        ConfigSkin {
3829            id: uuid!("c0ffee00-1234-5678-9abc-def012345678"),
3830            name: i18n::I18nString::Translated("Helmet".into()),
3831            unlock_description: Some(i18n::I18nString::Translated("Test helmet unlock".into())),
3832            code: "test_helmet".to_string(),
3833            skin_type: SkinType::Helmet,
3834            icon_url: "/skins/helmet_test.webp".to_string(),
3835            icon_path: "/skins/helmet_test.webp".to_string(),
3836            spine_path: "".to_string(),
3837            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3838            price: Some(vec![CurrencyUnit {
3839                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3840                amount: 200,
3841            }]),
3842            color: Some("".into()),
3843        },
3844        ConfigSkin {
3845            id: uuid!("a1b2c3d4-e5f6-7890-abcd-ef1234567892"),
3846            name: i18n::I18nString::Translated("Alt armor".into()),
3847            unlock_description: Some(i18n::I18nString::Translated("Alt armor unlock".into())),
3848            code: "test_armor_alt".to_string(),
3849            skin_type: SkinType::Armor,
3850            icon_url: "/skins/armor_alt.webp".to_string(),
3851            icon_path: "/skins/armor_alt.webp".to_string(),
3852            spine_path: "".to_string(),
3853            rarity_id: uuid!("8c8acba2-67d3-40e0-ac62-2f7acce64ccc"),
3854            price: None,
3855            color: Some("".into()),
3856        },
3857    ]
3858}
3859
3860fn generate_skins_settings() -> SkinsSettings {
3861    SkinsSettings {
3862        default_unlocked_skins: vec![uuid!("59a4dd34-b395-436f-8f81-2fb36ee1b714")],
3863        default_equipped_skins: vec![uuid!("a1b2c3d4-e5f6-7890-abcd-ef1234567890")],
3864    }
3865}
3866
3867fn generate_offers_templates() -> Vec<OfferTemplate> {
3868    vec![
3869        OfferTemplate {
3870            id: uuid!("0fab3fca-d35c-4fbd-8f95-4033e548be6f"),
3871            alias: "First Daily".to_string(),
3872            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3873            icon_path: String::new(),
3874            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3875            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
3876                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3877                amount: 50,
3878            }]),
3879            limit_of_buys: Some(3),
3880            buys_reset_seconds: Some(86400),
3881            limit_buy_text: None,
3882            events_subscribe: vec![],
3883            shop_tab: ShopTab::DailyDeals,
3884            enabled: true,
3885            flag_new: false,
3886            flag_sale: None,
3887            value: None,
3888            priority: 0,
3889        },
3890        OfferTemplate {
3891            id: uuid!("4af19145-037d-4d9b-b9a5-98e7d8c7b127"),
3892            alias: "Second Daily".to_string(),
3893            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3894            icon_path: String::new(),
3895            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3896            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
3897                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3898                amount: 50,
3899            }]),
3900            limit_of_buys: Some(1),
3901            buys_reset_seconds: Some(86400),
3902            limit_buy_text: None,
3903            events_subscribe: vec![],
3904            shop_tab: ShopTab::DailyDeals,
3905            enabled: true,
3906            flag_new: false,
3907            flag_sale: None,
3908            value: None,
3909            priority: 0,
3910        },
3911        OfferTemplate {
3912            id: uuid!("6fea60b3-db1c-4a20-a03c-94716a32afbc"),
3913            alias: "First triggered".to_string(),
3914            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3915            icon_path: String::new(),
3916            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3917            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
3918                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3919                amount: 50,
3920            }]),
3921            limit_of_buys: Some(2),
3922            buys_reset_seconds: Some(86400),
3923            limit_buy_text: None,
3924            events_subscribe: vec!["EnableAutoSell".to_string()],
3925            shop_tab: ShopTab::Resources,
3926            enabled: true,
3927            flag_new: false,
3928            flag_sale: None,
3929            value: None,
3930            priority: 0,
3931        },
3932        OfferTemplate {
3933            id: uuid!("11111111-1111-1111-1111-111111111111"),
3934            alias: "Disabled offer".to_string(),
3935            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3936            icon_path: String::new(),
3937            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3938            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
3939                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
3940                amount: 50,
3941            }]),
3942            limit_of_buys: Some(1),
3943            buys_reset_seconds: Some(86400),
3944            limit_buy_text: None,
3945            events_subscribe: vec![],
3946            shop_tab: ShopTab::DailyDeals,
3947            enabled: false,
3948            flag_new: false,
3949            flag_sale: None,
3950            value: None,
3951            priority: 0,
3952        },
3953        OfferTemplate {
3954            id: uuid!("22222222-2222-2222-2222-222222222222"),
3955            alias: "Free offer".to_string(),
3956            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3957            icon_path: String::new(),
3958            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3959            payment_type: PaymentType::Free,
3960            limit_of_buys: Some(1),
3961            buys_reset_seconds: Some(86400),
3962            limit_buy_text: None,
3963            events_subscribe: vec!["EnableAutoChest".to_string()],
3964            shop_tab: ShopTab::DailyDeals,
3965            enabled: true,
3966            flag_new: false,
3967            flag_sale: None,
3968            value: None,
3969            priority: 0,
3970        },
3971        OfferTemplate {
3972            id: uuid!("33333333-3333-3333-3333-333333333333"),
3973            alias: "Ad offer".to_string(),
3974            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3975            icon_path: String::new(),
3976            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3977            payment_type: PaymentType::Ad,
3978            limit_of_buys: Some(1),
3979            buys_reset_seconds: Some(86400),
3980            limit_buy_text: None,
3981            events_subscribe: vec!["DisableAutoChest".to_string()],
3982            shop_tab: ShopTab::Diamonds,
3983            enabled: true,
3984            flag_new: false,
3985            flag_sale: None,
3986            value: None,
3987            priority: 0,
3988        },
3989        OfferTemplate {
3990            id: uuid!("0b5cfa47-43bf-46db-930d-1d4a975f17d9"),
3991            alias: "Cash offer".to_string(),
3992            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
3993            icon_path: String::new(),
3994            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
3995            payment_type: PaymentType::RealMoney,
3996            limit_of_buys: Some(1),
3997            buys_reset_seconds: Some(86400),
3998            limit_buy_text: None,
3999            events_subscribe: vec!["DisableCaseUpgradePopUp".to_string()],
4000            shop_tab: ShopTab::Diamonds,
4001            enabled: true,
4002            flag_new: false,
4003            flag_sale: None,
4004            value: None,
4005            priority: 0,
4006        },
4007        // Triggered by DisableAutoSell
4008        OfferTemplate {
4009            id: uuid!("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
4010            alias: "Chain start offer".to_string(),
4011            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4012            icon_path: String::new(),
4013            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
4014            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
4015                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4016                amount: 50,
4017            }]),
4018            limit_of_buys: Some(1),
4019            buys_reset_seconds: Some(86400),
4020            limit_buy_text: None,
4021            events_subscribe: vec!["DisableAutoSell".to_string()],
4022            shop_tab: ShopTab::Resources,
4023            enabled: true,
4024            flag_new: false,
4025            flag_sale: None,
4026            value: None,
4027            priority: 0,
4028        },
4029        // Unlimited offer: no buy limit, added manually via NewOffer in tests.
4030        // Has a fake events_subscribe entry so it is not auto-created at character init.
4031        OfferTemplate {
4032            id: uuid!("dddddddd-dddd-dddd-dddd-dddddddddddd"),
4033            alias: "Unlimited offer".to_string(),
4034            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4035            icon_path: String::new(),
4036            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
4037            payment_type: PaymentType::Free,
4038            limit_of_buys: None,
4039            buys_reset_seconds: None,
4040            limit_buy_text: None,
4041            events_subscribe: vec!["_never".to_string()],
4042            shop_tab: ShopTab::DailyDeals,
4043            enabled: true,
4044            flag_new: false,
4045            flag_sale: None,
4046            value: None,
4047            priority: 0,
4048        },
4049        // Short-reset daily offer: auto-created, resets every 60 seconds (for reset tests)
4050        OfferTemplate {
4051            id: uuid!("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"),
4052            alias: "Short reset daily".to_string(),
4053            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4054            icon_path: String::new(),
4055            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
4056            payment_type: PaymentType::Free,
4057            limit_of_buys: Some(1),
4058            buys_reset_seconds: Some(60),
4059            limit_buy_text: None,
4060            events_subscribe: vec![],
4061            shop_tab: ShopTab::DailyDeals,
4062            enabled: true,
4063            flag_new: false,
4064            flag_sale: None,
4065            value: None,
4066            priority: 0,
4067        },
4068        // Progress Pass premium offer: lifetime one-shot (buys_reset_seconds: None),
4069        // no reward bundle (purchase effect is has_premium=true).
4070        OfferTemplate {
4071            id: uuid!("ff000000-0000-0000-0000-000000000001"),
4072            alias: "Progress Pass Premium".to_string(),
4073            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4074            icon_path: String::new(),
4075            reward_bundle_id: None,
4076            payment_type: PaymentType::InGameCurrency(vec![CurrencyUnit {
4077                currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4078                amount: 50,
4079            }]),
4080            limit_of_buys: Some(1),
4081            buys_reset_seconds: None,
4082            limit_buy_text: None,
4083            events_subscribe: vec![],
4084            shop_tab: ShopTab::ProgressPass,
4085            enabled: true,
4086            flag_new: false,
4087            flag_sale: None,
4088            value: None,
4089            priority: 0,
4090        },
4091        // Disabled triggered offer: subscribes to DisableAutoSell but must never be activated
4092        OfferTemplate {
4093            id: uuid!("cccccccc-cccc-cccc-cccc-cccccccccccc"),
4094            alias: "Disabled triggered offer".to_string(),
4095            title: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4096            icon_path: String::new(),
4097            reward_bundle_id: Some(uuid!("8838388b-6f13-4dc8-b0d4-561d8fe84da8")),
4098            payment_type: PaymentType::Free,
4099            limit_of_buys: Some(1),
4100            buys_reset_seconds: Some(86400),
4101            limit_buy_text: None,
4102            events_subscribe: vec!["DisableAutoSell".to_string()],
4103            shop_tab: ShopTab::DailyDeals,
4104            enabled: false,
4105            flag_new: false,
4106            flag_sale: None,
4107            value: None,
4108            priority: 0,
4109        },
4110    ]
4111}
4112
4113fn generate_shop_tabs() -> Vec<ShopTabConfig> {
4114    vec![
4115        ShopTabConfig {
4116            tab: ShopTab::DailyDeals,
4117            name: i18n::I18nString::Translated("Daily Deals".to_string()),
4118        },
4119        ShopTabConfig {
4120            tab: ShopTab::Diamonds,
4121            name: i18n::I18nString::Translated("Diamonds".to_string()),
4122        },
4123        ShopTabConfig {
4124            tab: ShopTab::Resources,
4125            name: i18n::I18nString::Translated("Resources".to_string()),
4126        },
4127        ShopTabConfig {
4128            tab: ShopTab::ProgressPass,
4129            name: i18n::I18nString::Translated("Progress Pass".to_string()),
4130        },
4131    ]
4132}
4133
4134fn generate_ratings_settings() -> Vec<RatingSettings> {
4135    vec![
4136        RatingSettings {
4137            id: uuid!("2a743358-aace-4404-8582-aae2c67bcb7b"),
4138            rating_type: RatingType::Arena,
4139            rating_range_rewards: vec![
4140                RatingRangeReward {
4141                    mail_template_id: Some(uuid!("98eea253-ac84-49ea-becb-4d5ef9c18b5c")),
4142                    diapason_start: 1,
4143                    diapason_end: Some(2),
4144                },
4145                RatingRangeReward {
4146                    mail_template_id: Some(uuid!("0042b76d-bfbe-4e02-a6a6-4881e229da88")),
4147                    diapason_start: 3,
4148                    diapason_end: Some(3),
4149                },
4150            ],
4151        },
4152        RatingSettings {
4153            id: uuid!("a4b3388c-6d77-437d-aa41-91c4850ab01a"),
4154            rating_type: RatingType::Power,
4155            rating_range_rewards: vec![],
4156        },
4157        RatingSettings {
4158            id: uuid!("998fa5ac-9bd6-4b19-a13a-2e8c7ad6fcbd"),
4159            rating_type: RatingType::PvE,
4160            rating_range_rewards: vec![],
4161        },
4162    ]
4163}
4164
4165fn generate_gatings() -> Gatings {
4166    Gatings {
4167        afk_rewards_button_unlock_chapter: 2,
4168        sidebar_navigation: SideBarNavigation {
4169            quests_button_unlock_chapter: 2,
4170            progress_pass_button_unlock_chapter: 2,
4171            arena_button_unlock_chapter: 2,
4172            ratings_button_unlock_chapter: 2,
4173            mail_button_unlock_chapter: 2,
4174        },
4175        party_unlock_chapter: 2,
4176        navbar_navigation: NavBarNavigation {
4177            castle: CastleGating {
4178                statue_unlock_chapter: 2,
4179                ..Default::default()
4180            },
4181            ..Default::default()
4182        },
4183        autochest: AutoChestGatings {
4184            chest_upgrade_button_unlock_chapter: 2,
4185            show_chest_click_tip_until_stage: 10,
4186            ..Default::default()
4187        },
4188        customization_screen_unlock_chapter: 37,
4189        ..Default::default()
4190    }
4191}
4192
4193pub fn generate_test_talents() -> Vec<TalentTemplate> {
4194    vec![
4195        TalentTemplate {
4196            id: uuid!("a1000000-0000-0000-0000-000000000001"),
4197            name: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4198            description: i18n::I18nString::new(
4199                "content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name",
4200            ),
4201            description_values_script: None,
4202            icon_url: String::new(),
4203            icon_path: String::new(),
4204            levels: vec![
4205                TalentLevel {
4206                    level: 1,
4207                    cost: CurrencyUnit {
4208                        currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4209                        amount: 100,
4210                    },
4211                    duration_sec: 10,
4212                    attribute_bonuses: vec![TalentAttributeBonus {
4213                        attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
4214                        value: 50,
4215                    }],
4216                    backend_modifiers: vec![],
4217                },
4218                TalentLevel {
4219                    level: 2,
4220                    cost: CurrencyUnit {
4221                        currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4222                        amount: 200,
4223                    },
4224                    duration_sec: 20,
4225                    attribute_bonuses: vec![TalentAttributeBonus {
4226                        attribute_id: uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08"),
4227                        value: 50,
4228                    }],
4229                    backend_modifiers: vec![],
4230                },
4231            ],
4232            unlock_condition: TalentUnlockCondition {
4233                required_talents: vec![],
4234                required_points: 0,
4235            },
4236            position: TalentPosition { col: 0, row: 0 },
4237        },
4238        TalentTemplate {
4239            id: uuid!("a1000000-0000-0000-0000-000000000002"),
4240            name: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4241            description: i18n::I18nString::new(
4242                "content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name",
4243            ),
4244            description_values_script: None,
4245            icon_url: String::new(),
4246            icon_path: String::new(),
4247            levels: vec![
4248                TalentLevel {
4249                    level: 1,
4250                    cost: CurrencyUnit {
4251                        currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4252                        amount: 150,
4253                    },
4254                    duration_sec: 30,
4255                    attribute_bonuses: vec![],
4256                    backend_modifiers: vec![TalentBackendModifier::TalentResearchSpeedPercent(
4257                        20.0,
4258                    )],
4259                },
4260                TalentLevel {
4261                    level: 2,
4262                    cost: CurrencyUnit {
4263                        currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4264                        amount: 300,
4265                    },
4266                    duration_sec: 60,
4267                    attribute_bonuses: vec![],
4268                    backend_modifiers: vec![TalentBackendModifier::TalentResearchSpeedPercent(
4269                        20.0,
4270                    )],
4271                },
4272            ],
4273            unlock_condition: TalentUnlockCondition {
4274                required_talents: vec![uuid!("a1000000-0000-0000-0000-000000000001")],
4275                required_points: 0,
4276            },
4277            position: TalentPosition { col: 1, row: 0 },
4278        },
4279        // Long-duration talent for partial-skip tests (duration > skip_currency_skips_sec=900).
4280        TalentTemplate {
4281            id: uuid!("a1000000-0000-0000-0000-000000000003"),
4282            name: i18n::I18nString::new("content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name"),
4283            description: i18n::I18nString::new(
4284                "content.skins.a1b2c3d4-e5f6-7890-abcd-ef1234567890:name",
4285            ),
4286            description_values_script: None,
4287            icon_url: String::new(),
4288            icon_path: String::new(),
4289            levels: vec![TalentLevel {
4290                level: 1,
4291                cost: CurrencyUnit {
4292                    currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4293                    amount: 100,
4294                },
4295                duration_sec: 2000,
4296                attribute_bonuses: vec![],
4297                backend_modifiers: vec![],
4298            }],
4299            unlock_condition: TalentUnlockCondition {
4300                required_talents: vec![],
4301                required_points: 0,
4302            },
4303            position: TalentPosition { col: 2, row: 0 },
4304        },
4305    ]
4306}
4307
4308fn generate_statue_bonus_grades() -> NonEmptyVec<StatueBonusGrade> {
4309    NonEmptyVec::new(vec![
4310        StatueBonusGrade {
4311            id: uuid!("a1000000-0000-0000-0000-000000000001"),
4312            name: i18n::I18nString::Translated("F".to_string()),
4313            color: "#808080".to_string(),
4314            order: 0,
4315        },
4316        StatueBonusGrade {
4317            id: uuid!("a1000000-0000-0000-0000-000000000002"),
4318            name: i18n::I18nString::Translated("D".to_string()),
4319            color: "#00aa00".to_string(),
4320            order: 1,
4321        },
4322        StatueBonusGrade {
4323            id: uuid!("a1000000-0000-0000-0000-000000000003"),
4324            name: i18n::I18nString::Translated("C".to_string()),
4325            color: "#0000ff".to_string(),
4326            order: 2,
4327        },
4328        StatueBonusGrade {
4329            id: uuid!("a1000000-0000-0000-0000-000000000009"),
4330            name: i18n::I18nString::Translated("SSS+".to_string()),
4331            color: "#ff0000".to_string(),
4332            order: 8,
4333        },
4334    ])
4335}
4336
4337fn generate_statue_settings() -> StatueSettings {
4338    StatueSettings {
4339        // statue currency
4340        currency_id: uuid!("b59b33a2-4d19-4e2c-9cea-e03ea15882a0"),
4341        roll_costs: NonEmptyVec::new(vec![
4342            StatueRollCostConfig {
4343                locked_count: 0,
4344                cost: PositiveI64::new(100),
4345            },
4346            StatueRollCostConfig {
4347                locked_count: 1,
4348                cost: PositiveI64::new(300),
4349            },
4350            StatueRollCostConfig {
4351                locked_count: 2,
4352                cost: PositiveI64::new(500),
4353            },
4354            StatueRollCostConfig {
4355                locked_count: 3,
4356                cost: PositiveI64::new(700),
4357            },
4358            StatueRollCostConfig {
4359                locked_count: 4,
4360                cost: PositiveI64::new(900),
4361            },
4362            StatueRollCostConfig {
4363                locked_count: 5,
4364                cost: PositiveI64::new(1200),
4365            },
4366        ]),
4367    }
4368}
4369
4370fn generate_statue_bonus_type_configs() -> NonEmptyVec<StatueBonusTypeConfig> {
4371    let grade_f = uuid!("a1000000-0000-0000-0000-000000000001");
4372    let grade_d = uuid!("a1000000-0000-0000-0000-000000000002");
4373    let grade_c = uuid!("a1000000-0000-0000-0000-000000000003");
4374    let grade_sss_plus = uuid!("a1000000-0000-0000-0000-000000000009");
4375    let attr_hp = uuid!("45eca0a7-7430-487b-bd65-b796c6d88c08");
4376    let attr_damage = uuid!("6ad485d7-9567-4b77-8ddc-a2418dd1dfe6");
4377
4378    NonEmptyVec::new(vec![
4379        StatueBonusTypeConfig {
4380            attribute_id: attr_hp,
4381            grade_values: NonEmptyVec::new(vec![
4382                StatueBonusGradeValue {
4383                    grade_id: grade_f,
4384                    value: PositiveI32::new(100),
4385                },
4386                StatueBonusGradeValue {
4387                    grade_id: grade_d,
4388                    value: PositiveI32::new(200),
4389                },
4390                StatueBonusGradeValue {
4391                    grade_id: grade_c,
4392                    value: PositiveI32::new(300),
4393                },
4394                StatueBonusGradeValue {
4395                    grade_id: grade_sss_plus,
4396                    value: PositiveI32::new(1200),
4397                },
4398            ]),
4399        },
4400        StatueBonusTypeConfig {
4401            attribute_id: attr_damage,
4402            grade_values: NonEmptyVec::new(vec![
4403                StatueBonusGradeValue {
4404                    grade_id: grade_f,
4405                    value: PositiveI32::new(100),
4406                },
4407                StatueBonusGradeValue {
4408                    grade_id: grade_d,
4409                    value: PositiveI32::new(200),
4410                },
4411                StatueBonusGradeValue {
4412                    grade_id: grade_c,
4413                    value: PositiveI32::new(300),
4414                },
4415                StatueBonusGradeValue {
4416                    grade_id: grade_sss_plus,
4417                    value: PositiveI32::new(1200),
4418                },
4419            ]),
4420        },
4421    ])
4422}
4423
4424fn generate_statue_level_configs() -> NonEmptyVec<StatueLevelConfig> {
4425    let grade_f = uuid!("a1000000-0000-0000-0000-000000000001");
4426    let grade_d = uuid!("a1000000-0000-0000-0000-000000000002");
4427    let grade_c = uuid!("a1000000-0000-0000-0000-000000000003");
4428    let grade_sss_plus = uuid!("a1000000-0000-0000-0000-000000000009");
4429
4430    NonEmptyVec::new(vec![
4431        StatueLevelConfig {
4432            level: 1,
4433            required_experience: 0,
4434            slot_count: NonZeroU64::new(3),
4435            sets_count: NonZeroU64::new(1),
4436            grade_weights: NonEmptyVec::new(vec![
4437                StatueBonusGradeWeight {
4438                    grade_id: grade_f,
4439                    weight: PositiveF64::new(5.0),
4440                },
4441                StatueBonusGradeWeight {
4442                    grade_id: grade_d,
4443                    weight: PositiveF64::new(3.0),
4444                },
4445                StatueBonusGradeWeight {
4446                    grade_id: grade_c,
4447                    weight: PositiveF64::new(2.0),
4448                },
4449            ]),
4450        },
4451        StatueLevelConfig {
4452            level: 2,
4453            required_experience: 200,
4454            slot_count: NonZeroU64::new(4),
4455            sets_count: NonZeroU64::new(2),
4456            grade_weights: NonEmptyVec::new(vec![
4457                StatueBonusGradeWeight {
4458                    grade_id: grade_f,
4459                    weight: PositiveF64::new(4.0),
4460                },
4461                StatueBonusGradeWeight {
4462                    grade_id: grade_d,
4463                    weight: PositiveF64::new(3.0),
4464                },
4465                StatueBonusGradeWeight {
4466                    grade_id: grade_c,
4467                    weight: PositiveF64::new(2.0),
4468                },
4469                StatueBonusGradeWeight {
4470                    grade_id: grade_sss_plus,
4471                    weight: PositiveF64::new(1.0),
4472                },
4473            ]),
4474        },
4475    ])
4476}
4477
4478pub fn generate_game_config_for_tests() -> GameConfig {
4479    let mut game_config = GameConfig {
4480        attributes: generate_attributes(),
4481        item_cases_settings: generate_item_cases_settings(),
4482        game_settings: generate_game_settings(),
4483        ads_settings: generate_ads_settings(),
4484        items: vec![],
4485        item_rarities: generate_item_rarities(),
4486        skins: generate_skins(),
4487        skins_settings: generate_skins_settings(),
4488        effects: generate_effects(),
4489        abilities: generate_abilities(),
4490        ability_cases_settings: generate_ability_cases_settings(),
4491        ability_rarities: generate_ability_rarities(),
4492        ability_levels: generate_ability_levels(),
4493        fight_settings: generate_fight_settings(),
4494        entities: generate_entities(),
4495        fight_templates: generate_fight_templates(),
4496        dungeon_templates: generate_dungeon_templates(),
4497        chapters: generate_chapters(),
4498        character_levels: generate_character_levels(),
4499        ability_slots_levels: generate_ability_slots_levels(),
4500        patron_levels: generate_patron_levels(),
4501        quests: generate_quests(),
4502        quests_progression_settings: generate_quests_progression_settings(),
4503        vassals_settings: generate_vassals_settings(),
4504        vassal_tasks: generate_vassal_tasks(),
4505        pvp_settings: generate_pvp_settings(),
4506        gifts: generate_gifts(),
4507        currencies: generate_currencies(),
4508        inventory_levels: generate_inventory_levels(),
4509        arena_settings: generate_arena_settings(),
4510        arena_leagues: generate_arena_leagues(),
4511        matchmaking_settings: generate_matchmaking_settings(),
4512        event_descriptions: generate_event_descriptions(),
4513        classes: generate_classes(),
4514        class_levels: vec![],
4515        projectiles: generate_projectiles(),
4516        mail_templates: generate_mail_templates(),
4517        bundles: generate_bundles(),
4518        ability_presets_settings: generate_ability_presets_settings(),
4519        bots_settings: generate_bots_settings(),
4520        reports_settings: generate_reports_settings(),
4521        afk_rewards_settings: generate_afk_rewards_settings(),
4522        afk_rewards_levels: generate_afk_rewards_levels(),
4523        users_generating_settings: generate_users_generating_settings(),
4524        tutorial_steps: vec![],
4525        chats_settings: vec![],
4526        offers_templates: generate_offers_templates(),
4527        shop_tabs: generate_shop_tabs(),
4528        ratings_settings: generate_ratings_settings(),
4529        cheat_scripts: vec![],
4530        test_player_scripts: vec![],
4531        gatings: generate_gatings(),
4532        pet_rarities: generate_pet_rarities(),
4533        pet_templates: generate_pet_templates(),
4534        pet_levels: generate_pet_levels(),
4535        pet_slots_levels: generate_pet_slots_levels(),
4536        pet_cases_settings: generate_pet_cases_settings(),
4537        talent_tree_settings: TalentTreeSettings {
4538            time_skip_ticket_skips_sec: 1800,
4539            skip_currency_id: uuid!("6c050b07-5282-4a23-8bbf-dabecd27cade"),
4540            skip_currency_skips_sec: 900,
4541        },
4542        talents: generate_test_talents(),
4543        statue_bonus_grades: generate_statue_bonus_grades(),
4544        statue_bonus_type_configs: generate_statue_bonus_type_configs(),
4545        statue_level_configs: generate_statue_level_configs(),
4546        statue_settings: generate_statue_settings(),
4547        progress_pass: ProgressPassConfig {
4548            premium_offer_template_id: uuid!("ff000000-0000-0000-0000-000000000001"),
4549            tiers: vec![
4550                ProgressPassTierTemplate {
4551                    tier: 1,
4552                    quest_template_ids: vec![uuid!("aa000000-0000-0000-0000-000000000001")],
4553                    free_reward_bundle_id: uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82"),
4554                    paid_reward_bundle_id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
4555                },
4556                ProgressPassTierTemplate {
4557                    tier: 2,
4558                    quest_template_ids: vec![
4559                        uuid!("aa000000-0000-0000-0000-000000000001"),
4560                        uuid!("bb000000-0000-0000-0000-000000000002"),
4561                    ],
4562                    free_reward_bundle_id: uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82"),
4563                    paid_reward_bundle_id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
4564                },
4565                ProgressPassTierTemplate {
4566                    tier: 3,
4567                    quest_template_ids: vec![uuid!("cc000000-0000-0000-0000-000000000003")],
4568                    free_reward_bundle_id: uuid!("9cc6c6e4-e87f-4443-99ce-2f88b2bdbe82"),
4569                    paid_reward_bundle_id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
4570                },
4571            ],
4572        },
4573        buff_templates: vec![BuffTemplate {
4574            id: uuid!("b2c3d4e5-f6a7-8901-bcde-f12345678901"),
4575            title: i18n::I18nString::Translated("Daily Booster x1.5".to_string()),
4576            description: i18n::I18nString::Translated(
4577                "Exp and currency gain multiplied by 1.5 until end of day".to_string(),
4578            ),
4579            icon_path: String::new(),
4580            effect: BuffEffect::CurrencyExpBoost {
4581                multiplier: 1.5,
4582                currency_id: uuid!("00000000-0000-0000-0000-000000000000"),
4583            },
4584        }],
4585        bird_variants: vec![
4586            BirdVariant {
4587                id: uuid!("d1e2f3a4-b5c6-7890-abcd-ef1234567891"),
4588                spine_path: "/bird_variant_1".to_string(),
4589                bundle_id: uuid!("53e8ffaa-7ee4-4612-bbfc-bb157979ca8d"),
4590            },
4591            BirdVariant {
4592                id: uuid!("d1e2f3a4-b5c6-7890-abcd-ef1234567892"),
4593                spine_path: "/bird_variant_2".to_string(),
4594                bundle_id: uuid!("e18fc101-6615-440c-9a1d-42f509986ccc"),
4595            },
4596        ],
4597    };
4598
4599    game_config.items = generate_items(&game_config.item_rarities);
4600
4601    game_config
4602}