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

177 lines
13 KiB
Markdown
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.
# План: ребаланс прогрессии и экономики (Этап 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, при расхождении — скорректировать.