Files
fishing-game/docs/PLAN-PROGRESSION.md
andrey 1ebaf6e2ae Этап 53: ребаланс прогрессии и экономики + масштабируемые квесты. (1) Цены снастей: RODS 0/875/4500/15000 → 0/150/500/30000; LURES 0/625/3000/11250 → 0/100/2000/22000 (Воблер 300→2000 по правке владельца). Апгрейды id 0: ROD_UPG_COST 70/210/500 → 20/50/100, LURE_UPG_COST 60/160/400 → 15/40/80; UPG_MULT 0.2/0.6/1.2 → 0.15/0.35/0.6. Гейт «предыдущая снасть на 4 ур.» оставлен, но апгрейды сильно удешевлены. (2) Цены локаций: Озёра 65536→500, Болото 90000→10000, Море 131072→100000, Океан 196608→300000; порядок по цене Река<Озёра<Болото<Море<Океан сохранён. (3) Веса Болота снижены до уровня Озёр и ниже (цель «тащить легче, доход меньше»): SWAMP_DAY_WEIGHTS={glowfin:4,moonfish:32,emberfin:3,violetlure:6,spiritfin:7}, SWAMP_NIGHT_WEIGHTS={glowfin:4,moonfish:28,emberfin:3,violetlure:10,spiritfin:3}; per-catch E 240.3/328.9 → 133.9/162.5 (доля дешёвой лёгкой moonfish поднята, дорогая violetlure/emberfin срезана); по 🪙/мин Болото ≈ Озёра. Инвариант balance.mjs «дороже вода доходнее» для Болота сознательно не выполняется. (4) Квесты дня масштабируются по save.earned: questScale()=clamp(round((earned/2000)^0.6),1,30); QUEST_TPLS масштабирует ВСЕ шаблоны (earn_coins goal×scale, casts ×(1+0.15·scale), catch_weight порог от localMedianW() — медиана середин весов рыб ТЕКУЩЕЙ локации ×scale^0.35, catch_rarity r=clamp(1+floor(1.5·log10(scale+1)),1,4), catch_species вид из SPECIES_BY_LOCATION[save.location] с rarity≤2), qReward(base)=round(base·scale^0.6); questText RU/EN терпим к неречным id (fallback trName). (5) Новый tools/progression.mjs (read-only, данные из index.html): моделирует улов (pickSpecies+rollWeight+варианты+обрыв по maxW) и цикл ловли (biteChance/таймеры/fishForce+updateReel ботом), жадный маршрут покупок → 🪙/мин по водам и ETA целей; what-if --rod/--lure/--loc/--rod-upg/--lure-upg/--upg-mult/--set/--set-day/--set-night. Калибровочные цели: Стекло 4.4 мин · Озёра 10.3 (5.9 после Стекло) · Карбон 6.9 · Болото 22.9 (13.3 после Карбона) · Титан ~50 мин · Море 2 ч 17 · Океан 4 ч 04. (6) Тесты 233→234: обновлены пины M5 (150/100, апгрейды 20/50/100 и 15/40/80, upgCost-строки), lc1 (costs 0,500,100000,300000,10000), lc8 (покупки локаций), ранний магазин; новый §9e2 — questScale/localMedianW/рост целей. Прогон: 234/234 PASS, exit 0; check.mjs OK; balance.mjs — Болото 133.9/162.5, остальные пины (Река/Озёра/Море/Океан) не сдвинуты. (7) Доки: AGENTS.md (Баланс/Локации/Баланс Озёр/Баланс-скрипт + пункт «Прогрессия»/Награды + тест-глобалы), README (локации/цены/прогрессия), docs/PLAN-PROGRESSION.md (новый), DEVLOG (Этап 53).
2026-10-05 15:42:49 +03:00

13 KiB
Raw Permalink Blame History

План: ребаланс прогрессии и экономики (Этап 53, в работе)

Статус: реализован (Этап 53) — см. запись «Этап 53» в docs/DEVLOG.md. Финальные цены: Стекло/Червь 150/100, Карбон/Воблер 500/2000, Титан/Блёстка 30000/22000; апгрейды 20/50/100 и 15/40/80, UPG_MULT 0.15/0.35/0.6; Озёра 500, Болото 10000, Море 100000, Океан 300000. Веса Болота — день 4/32/3/6/7, ночь 4/28/3/10/3 (per-catch 133.9/162.5). Квесты масштабируются по save.earned. Тело плана ниже — историческая фиксация решения. Ссылки на строки — на момент составления плана. Ориентир по коду: index.html ~5608 строк.

1. Задача

Ранняя игра должна быстро давать апгрейды (2-я удочка/приманка и первая новая локация), дальше прогресс должен плавно замедляться без «застревания», а поздние цели — занимать несколько игровых сессий (ориентир: 15 минут в день × 2–3 дня на удочку «Титан»).

Дополнительно: ежедневные задания должны масштабироваться по прогрессу игрока, чтобы оставаться осмысленными и не доминировать на поздних этапах.

2. Зафиксированные решения (ответы владельца)

Развилка Решение
Темп раннего этапа 2-я удочка + 2-я приманка + Озёра ≈ 4–6 минут (гарантированно < 5 мин по опыту)
Что меняем Только цены снастей/локаций + веса рыб Болота + логика квестов. Доходность остальных вод не трогаем
Гейт лавки Оставляем «предыдущая снасть на 4 ур.», но сильно удешевляем апгрейды
Локации Озёра 500 · Болото 5 000 · Море 100 000 · Океан 200 000
Болото Перебалансировать веса рыб, чтобы доходность стала примерно как у Озёр (~194/249 🪙)
Титан ~1 час игры, апгрейды Титана — опциональны и в расчёт до Моря не входят
Море / Океан ~2 часа / ~4 часа игры (задаётся ценой; проверить progression.mjs)
Ежедневные задания Масштабировать все шаблоны; метрика прогресса — save.earned
Стартовый капитал Не выдаём

3. Целевая кривая прогрессии

Времена — накопительные от старта сессии, фаза — самая выгодная доступная вода.

# Цель Когда Цена Текущая цена
1 Дедова удочка 1→4 ур. ~1 мин апгрейды 20/50/100 70/210/500
2 Стеклопластик + Червь ~2–3 мин 150 + 100 875 + 625
3 Озёра < 5 мин 500 65 536
4 Карбон + Воблер 5–10 мин 500 + 300 4 500 + 3 000
5 Болото +15 мин после Карбона и 2-й приманки 5 000 90 000
6 Блёстка ~40–50 мин 22 000 11 250
7 Титан (без апгрейдов) ~1 час 30 000 15 000
8 Апгрейды Титана/Блёстки (опция) 1–2 ч из UPG_MULT —
9 Море ~2 часа 100 000 131 072
10 Океан ~4 часа 200 000 196 608

Порядок вод по цене сохраняется: Озёра (500) < Болото (5 000) < Море (100 000) < Океан (200 000).

4. Цены (первый проход)

Константа Где Сейчас Стало
RODS cost index.html:2226-2230 0 / 875 / 4500 / 15000 0 / 150 / 500 / 30000
LURES cost :2232-2237 0 / 625 / 3000 / 11250 0 / 100 / 300 / 22000
ROD_UPG_COST :2240 70 / 210 / 500 20 / 50 / 100
LURE_UPG_COST :2241 60 / 160 / 400 15 / 40 / 80
UPG_MULT :2242 0.2 / 0.6 / 1.2 0.15 / 0.35 / 0.6
Озёра cost :2088 65536 500
Болото cost :2097 90000 5000
Море cost :2091 131072 100000
Океан cost :2094 196608 200000

Апгрейды id>0 считаются upgCost() (:2250) от новой базы — формула не меняется.

Калибровка progression.mjs (what-if с ценами выше и весами Болота из раздела 5):

Цель Модель Целевое Комментарий
Стеклопластик 4.5 мин < 5 мин ок
Озёра 8.1 мин (3.6 после Стекло) < 5 мин после Стекло ок
Карбон 7.1 мин 5–10 мин ок
Болото (цена 5000) 14.2 мин +15 мин после Карбона/Воблера от Карбона 6.7 мин — мало; под 15 мин цена ≈ 12 000
Титан 32.5 мин (44 мин при Болоте 12000) 2–3 дня × 15 мин = 30–45 мин ок для чистой игры
Море 1 ч 37 мин (при Болоте 12000 ≈ 1 ч 46) ~2 ч близко
Океан 2 ч 48 мин (при Болоте 12000 ≈ 2 ч 57) ~4 ч мало; при необходимости поднять цену

Модель — «идеальный» игрок и оптимистична (реальная игра медленнее на промахи/меню), поэтому реальные времена будут выше модельных — цели по реальной игре могут сойтись. Итог по цене Болота: 5000 даёт ~7 мин, для целевых 15 мин нужно ~12 000 (уточнить у владельца).

5. Веса рыб Болота (снизить доход до уровня Озёр)

Цель: SWAMP_*_WEIGHTS дают день ≈194 / ночь ≈249 🪙 (как Озёра). Текущие 240.3/328.9. Двигаем доли (умножение всех весов доход не меняет). Подобраны точные векторы:

Таблица glowfin moonfish emberfin violetlure spiritfin E, 🪙
SWAMP_DAY_WEIGHTS 8 5 28 8 8 194.1
SWAMP_NIGHT_WEIGHTS 4 8 12 14 3 249.0

Все веса ≥3 (тест «каждый вид ≥1» за 3000 роллов с запасом). Ночь богаче долей violetlure (14 против 8), день — долей emberfin. Финал сверить node tools/balance.mjs после правки.

Важно (расхождение метрик): per-catch E совпадает с Озёрами, но 🪙/мин у Болота всё равно выше (~1800 против ~1400, tools/progression.mjs): болотная рыба легче и бой короче, цикл быстрее. Если владелец имел в виду паритет именно по 🪙/мин, веса Болота нужно опустить сильнее (≈−25%) — уточнить.

Внимание: это ломает инвариант balance.mjs «каждая новая (по цене) вода доходнее предыдущей в ОБЕ фазы» (Болото/Озёра станет ≈1.0). Инвариант и пины в шапке balance.mjs обновить осознанно.

6. Ежедневные задания с масштабированием

  • Метрика P = save.earned (только доход с рыбалки; награды квестов его не разгоняют).
  • questScale() = clamp(round((P/2000)^0.6), 1, 30).
  • QUEST_TPLS (:2488) — масштабируем все:
    • earn_coins: goal = base(150/250/400)·scale, reward = round(goal·0.25);
    • casts: goal = base(8/10/15)·(1+scale·0.15);
    • catch_species: вид — из текущей воды (SPECIES_BY_LOCATION[save.location]), цель 3–5;
    • catch_weight: param — от медианного веса рыб воды (localMedianW()), не 2/3/5 кг;
    • catch_rarity: param = clamp(1+floor(log10(scale+1)), 1, 4);
    • catch_shiny: цель 1, растёт награда.
  • Итог: 3 квеста/день ≈ 5–10 минут текущего дохода на любом этапе.

7. Инструмент tools/progression.mjs (новый)

По образцу tools/balance.mjs — чистое чтение index.html:

  • вырезает данные (SPECIES, таблицы локаций, VARIANTS, RODS, LURES, ROD/LURE_UPG_COST, UPG_MULT, LOCATIONS);
  • моделирует улов: pickSpecies + rollWeight (стат size) + ожидаемый множитель вариантов (буст rare) + обрыв, если w > rod.maxW;
  • время цикла: biteChance (:2974), таймер клёва (:3178), fishForce/updateReel (:3021/:3043) — бот «держать в затишье, отпускать в рывке»;
  • жадный путь покупок по маршруту (по умолчанию — цели раздела 3) → печатает доход по этапам (🪙/мин) и ETA каждой цели;
  • флаги --rod/--lure/--loc/--rod-upg/--lure-upg/--upg-mult (what-if), --start-coins, --per-day <мин>, --route, --help.

8. Карта изменений по коду (index.html)

Что Где Правка
Цены снастей/апгрейдов :2226-2242 новые числа (раздел 4)
Цены локаций :2084-2100 новые числа (раздел 4)
Веса Болота :2148-2149 новые SWAMP_DAY/NIGHT_WEIGHTS (раздел 5)
Квесты :2488-2501 questScale(), масштаб goal/reward, localMedianW()
i18n подписи T при необходимости — подписи новых шаблонов

Не трогаем: catchFish()/экономику улова, доходность Реки/Озёр/Моря/Океана, физику боя, формат сейва (новых персистентных полей нет).

9. Тесты (tests/test.js) — в том же коммите

  • M5: :1271-1272 ('875 🪙'/'625 🪙'), :1379-1380 (покупка Стеклопластика и остаток), :1383-1387 (апгрейд), :1390-1397 (строка upgCost).
  • lc1: :2035 (costs → 0,500,100000,200000,5000).
  • lc8: :2240-2338 (остатки монет при покупках).
  • Новые: questScale/масштаб QUEST_TPLS, localMedianW.
  • balance.mjs: обновить пины Болота (и, при решении, инвариант).

10. Проверка (порядок команд)

  1. node tools/check.mjs
  2. node tools/balance.mjs — Болото в цели, остальные пины не сдвинуты
  3. node tools/progression.mjs — ETA целей совпадают с разделом 3
  4. cd tests && npm test — все PASS, exit 0
  5. Плейтест первых 5 минут + симуляция «15 мин/день × 2–3 дня»
  6. При релизе: node tools/minify.mjs

11. Риски и открытые вопросы

  1. Болото ≈ Озёра ломает инвариант «дороже вода = доходнее» — принято осознанно.
  2. Море/Океан дают меньше 🪙/мин, чем Озёра/Болото (длиннее бой, ниже доля удержания) — это существующая особенность баланса рыб; задаём только цену. Отдельная задача, если владелец захочет поднять их доход.
  3. Разброс RNG (варианты/золотая рыбка) — «< 5 мин» гарантируется с запасом квестами первого дня; строгого детерминизма не будет.
  4. Точные цены Моря/Океана (100000/200000) — по решению владельца; progression.mjs покажет итоговые ETA, при расхождении — скорректировать.