Files

272 lines
12 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"_meta": {
"file": "balance.json",
"version": "1.1",
"rules": "docs/GDD.md (компактная сводка) + docs/DECISIONS.md (D01–D17)",
"note": "null = параметр не задан в постановке, уточнить до кода (см. _todo). Никаких выдуманных чисел.",
"_todo": [
"attacks.junk.spawn_probability — не задан в спецификации (явно null)",
"income_target_by_hour: часы 4,6,7,8 — интерполяция, уточнить",
"difficulty.h2 packet_timer/request_timer: формула даёт 26.325/50.15 (19.5×1.35 и 29.5×1.7 — у запросов отдельный grace)"
]
},
"constants": {
"hour_seconds": 300,
"run_hours": 9,
"sla_start": 128,
"sla_max": 200,
"money_start": 150,
"buffer_base": 4,
"buffer_per_upgrade": 2,
"buffer_max": 8,
"slots_start": 2,
"slots_max": 4,
"max_sections": 6,
"files_per_folder": 16,
"folders_per_section": 12,
"send_window_visible_cards": 4,
"send_scroll_card_height_px": 56,
"required_name_char_limit": 12,
"file_cooldown_after_send_sec": 20,
"required_per_request": { "min": 1, "max": 3 }
},
"types": {
"text": {
"name_ru": "Текст",
"ext": ".txt",
"icon": "▤",
"recv_time": 1.0,
"send_time": 1.0,
"recv_fee": 2,
"base_pay": 20,
"weight": 6,
"minigame_coeff": 1.0,
"sla_loss": 2
},
"sound": {
"name_ru": "Звук",
"ext": ".wav",
"icon": "♪",
"recv_time": 1.5,
"send_time": 2.0,
"recv_fee": 3,
"base_pay": 35,
"weight": 10,
"minigame_coeff": 2.0,
"sla_loss": 4
},
"photo": {
"name_ru": "Фото",
"ext": ".jpg",
"icon": "▣",
"recv_time": 2.0,
"send_time": 3.0,
"recv_fee": 5,
"base_pay": 55,
"weight": 14,
"minigame_coeff": 3.0,
"sla_loss": 8
},
"video": {
"name_ru": "Видео",
"ext": ".mp4",
"icon": "▶",
"recv_time": 3.0,
"send_time": 5.0,
"recv_fee": 8,
"base_pay": 90,
"weight": 22,
"minigame_coeff": 4.0,
"sla_loss": 16
}
},
"difficulty": [
{ "hour": 1, "recv_interval": 12, "send_interval": 22, "max_requests": 2, "buffer": 4, "packet_timer": 30, "request_timer": 60, "attacks": 0 },
{ "hour": 2, "recv_interval": 11, "send_interval": 20, "max_requests": 2, "buffer": 4, "packet_timer": 26.325, "request_timer": 50.15, "attacks": 1 },
{ "hour": 3, "recv_interval": 10, "send_interval": 18, "max_requests": 3, "buffer": 5, "packet_timer": 22.8, "request_timer": 40.6, "attacks": 1 },
{ "hour": 4, "recv_interval": 9, "send_interval": 17, "max_requests": 3, "buffer": 5, "packet_timer": 18.5, "request_timer": 28.5, "attacks": 2 },
{ "hour": 5, "recv_interval": 8, "send_interval": 15, "max_requests": 4, "buffer": 6, "packet_timer": 18, "request_timer": 28, "attacks": 2 },
{ "hour": 6, "recv_interval": 7.5, "send_interval": 14, "max_requests": 4, "buffer": 6, "packet_timer": 17.5, "request_timer": 27.5, "attacks": 3 },
{ "hour": 7, "recv_interval": 7, "send_interval": 13, "max_requests": 4, "buffer": 6, "packet_timer": 17, "request_timer": 27, "attacks": 3 },
{ "hour": 8, "recv_interval": 6.5, "send_interval": 12, "max_requests": 4, "buffer": 7, "packet_timer": 16.5, "request_timer": 26.5, "attacks": 4 },
{ "hour": 9, "recv_interval": 6, "send_interval": 12, "max_requests": 4, "buffer": 7, "packet_timer": 16, "request_timer": 26, "attacks": 4 }
],
"difficulty_rules": {
"table_end_hour": 8,
"after_end_hour": "значения часа 8; +5% к скорости спавна каждые 2 часа",
"spawn_speedup_after_end": 0.05,
"spawn_speedup_period_hours": 2,
"type_availability": "час 1 — text; час 2 — text и sound; час 3 — +photo; час 4+ — все 4 (D23); атаки — с часа 2 (attack_junk)",
"timer_grace": "packet_timer: grace h1 1.5, h2 1.35, h3 1.2, h4+ 1.0 (Economy.TIMER_GRACE). request_timer: отдельный grace h1 2.0, h2 1.7, h3 1.4, h4+ 1.0 (Economy.REQUEST_TIMER_GRACE). Формула: (base − 0.5*(h−1))*grace + 4*level. h2: packet 19.5*1.35=26.325, request 29.5*1.7=50.15."
},
"progression": {
"unlocks": {
"shop": {"run_hour": 2, "label": "Магазин"},
"search": {"meta": "survive_hour_3", "label": "Поиск"},
"shield": {"meta": "survive_hour_5", "label": "Щит"},
"minigame_text": {"run_hour": 1},
"minigame_sound": {"run_hour": 2},
"minigame_photo": {"run_hour": 3},
"minigame_video": {"run_hour": 4},
"minigame_advanced": {"meta": "complete_run", "label": "Продвинутые мини-игры"},
"attack_junk": {"run_hour": 2},
"attack_ddos": {"run_hour": 2},
"attack_phishing": {"run_hour": 3},
"attack_ransomware": {"run_hour": 4}
},
"meta_rewards": {
"survive_hour_3": {"min_hours": 3, "unlocks": ["search"]},
"survive_hour_5": {"min_hours": 5, "unlocks": ["shield"]},
"complete_run": {"min_hours": 9, "unlocks": ["minigame_advanced"]}
}
},
"timers": {
"packet_timer": 20,
"request_timer": 30,
"attack_alert": 3.0,
"minigame_timeout": null,
"delete_long_press_sec": 0.5
},
"sla": {
"recv_bonus": 0.5,
"send_bonus": 1.0,
"reflect_bonus": 1.0,
"timeout_fine_base": 10,
"timeout_fine_per_hour": 2,
"timeout_fine_formula": "-(10 + 2*hour) — таймаут и подобные штрафы (D12)",
"wrong_attach_fine": -2,
"lost_file_fine": -5,
"buffer_overflow_fine": -5,
"sla_lose": "SLA <= 0"
},
"payout": {
"base_pay": "см. types.*.base_pay (значения в types)",
"recv_fee": "см. types.*.recv_fee (значения в types)",
"speed_formula": "speed = 0.6 + 0.4*(time_left / timer_total)",
"quality_formula": "quality = 0.5 + 0.5*mini_quality",
"multi_formula": "multi = 1 + 0.1*(n - 1)",
"protocol_mult": { "TCP": 1.15, "UDP": 1.0 },
"streak_formula": "streak = 1 + 0.02*min(10, streak)",
"income_target_by_hour": {
"hours": [1, 2, 3, 5, 9],
"approx": [500, 800, 1200, 1800, 2200],
"note": "ожидаемо ±10%; часы 4,6,7,8 — интерполяция, уточнить"
}
},
"connections": {
"W_formula": "W = clamp(0.30 - 0.005*(hour-1) - 0.005*successes + 0.05*zone_upgrade_level, 0.18, 0.36)",
"W_base": 0.3,
"W_hour_coef": -0.005,
"W_success_coef": -0.005,
"W_zone_bonus_per_level": 0.05,
"W_min": 0.18,
"W_max": 0.36,
"bar_speeds_px_per_sec": [440, 340, 280],
"hit_window_ms": [130, 200]
},
"channel": {
"CHANNEL_BG_BASE": 0,
"CHANNEL_BG_PER_HOUR": 0,
"SLOT_LOAD": 0,
"BG_note": "фоновый шум и занятые слоты НЕ грузят канал; load = только активные передачи (loading/sending)",
"CHANNEL_CAPACITY": 80,
"capacity_per_upgrade": 25,
"capacity_upgrade_max_level": 4,
"formula": "load = sum(weight(active_transfers)); factor = max(1.0, load / CHANNEL_CAPACITY); actual_time = base_time * factor. idle load = 0"
},
"attacks": {
"junk": {
"name_ru": "Мусорный пакет",
"spawn_probability": null,
"duration_sec": 15,
"tell": "серая иконка ?, размер 0 Б, нет таймера",
"effect": "авто-занос через duration_sec, занимает место в приёме; уничтожить можно как malicious в любой фазе (D02)",
"reward_money": 5,
"reward_sla": 1,
"fail_money": -10,
"fail_sla": -5,
"filter_disabled_sec": 10
},
"ddos": {
"name_ru": "DDoS",
"cards_min": 8,
"cards_max": 12,
"spawn_window_sec": 2.0,
"shield_hold_sec": 1.5,
"tell": "8–12 идентичных карточек без типа и таймера",
"effect": "волна карточек; отбивается удержанием щита",
"reward_money": 30,
"reward_sla": 2,
"fail_sla": -15,
"channel_debuff": 0.4,
"channel_debuff_sec": 15,
"packets_lost": 2,
"recv_disabled_sec": 5
},
"phishing": {
"name_ru": "Фишинг",
"reward_money": 20,
"reward_sla": 2,
"fail_money": -40,
"fail_sla": -10,
"file_lock_sec": 60,
"send_disabled_sec": 5,
"timeout_money": -20,
"timeout_sla": -5,
"timeout_lock_sec": 30,
"tell": "client_id формата id_XXXX с неверным символом (например id_7F3К — кириллическая К), серый аватар",
"effect": "фальшивый запрос/пакет"
},
"ransomware": {
"name_ru": "Шифровальщик",
"reward_money": 25,
"reward_sla": 2,
"folder_block_delay_sec": 3,
"auto_unlock_sec": 30,
"auto_unlock_money": -30,
"auto_unlock_sla": -10,
"tell": "расширение .exe, красный квадрат 4×4",
"effect": "файл становится locked (lock_until), кликабелен для уничтожения (D08)"
}
},
"shop": [
{ "id": "shop_slot3", "name_ru": "Третий слот", "effect": "connection_slots", "value": 1, "price": 250, "max_level": 1 },
{ "id": "shop_slot4", "name_ru": "Четвёртый слот", "effect": "connection_slots", "value": 1, "price": 450, "max_level": 1 },
{ "id": "shop_buffer", "name_ru": "Буфер +2", "effect": "buffer_slots", "value": 2, "price": 200, "max_level": 2 },
{ "id": "shop_timer", "name_ru": "Таймер пакетов +4 с", "effect": "packet_timer", "value": 4, "unit": "сек (аддитивно)", "price": 350, "max_level": 3 },
{ "id": "shop_zone", "name_ru": "Зона +5%", "effect": "zone_width", "value": 0.05, "unit": "доля W (аддитивно в формуле D04)", "price": 300, "max_level": 3 },
{ "id": "shop_channel", "name_ru": "Канал +25", "effect": "channel_capacity", "value": 25, "price": 250, "max_level": 4 },
{ "id": "shop_section", "name_ru": "Новая секция", "effect": "sections", "value": 1, "price": 300, "max_level": 5 },
{ "id": "shop_search", "name_ru": "Поиск", "effect": "search_highlight", "value": 1, "price": 250, "max_level": 1 },
{ "id": "shop_shield", "name_ru": "Щит", "effect": "shield", "value": 1, "price": 400, "max_level": 1 },
{ "id": "shop_sla", "name_ru": "SLA +24", "effect": "sla_add", "value": 24, "price": 300, "max_level": 3 }
],
"shop_reserve": {
"items": ["scanner", "autosort"],
"note": "резерв — в прототип НЕ входят (D13); позиций в shop НЕТ"
},
"spawn": {
"type_pool_by_hour": {
"1": ["text"],
"2": ["text", "sound"],
"3+": ["text", "sound", "photo", "video"]
},
"malicious_ratio": 0.0,
"required_count_by_hour": {
"1": { "1": 1.0 },
"2": { "1": 0.75, "2": 0.25 },
"3+": { "1": 0.6, "2": 0.3, "3": 0.1 }
},
"required_size_distribution": { "1": 0.6, "2": 0.3, "3": 0.1 },
"required_count_note": "required_count_by_hour — распределение по часу; required_size_distribution — fallback/час 3+",
"attack_schedule": "с часа 2, далее по difficulty.attacks, окно 60–240 с часа, не во время мини-игры"
},
"minigame_selection": {
"coeff": { "text": 1.0, "sound": 2.0, "photo": 3.0, "video": 4.0 },
"difficulty_formula": "sum(coeff(required)) / n",
"thresholds": { "text": "< 1.5", "sound": "< 2.5", "photo": "< 3.5", "else": "video" },
"call": "MiniGame.start(type, difficulty)",
"quality_stub": 1.0
}
}