Релиз 5 «Симулятор»: доки спринта 4 (DEVLOG этап 15, AGENTS «Физика боя», README механика) + харденинг escape-теста (пинн aggr/escape — флейк при ag≥0.65). 68/68 ×3, exit 0
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
- Ночь (M3): длительность суток `DAY_LENGTH` (сек), ночная таблица рыб `SPECIES_NIGHT`, фонарик — `LURES id=4` (секция «M3: Цикл дня/ночи»).
|
||||
- Босс (M4): тест-форс появления `forceBoss`, фазы боя `stateBoss`/`bossPhase`, босс-ветки в `updateReel()` (обрыв фазы) и `SNAP` в `updateGame()` (авто-переход), награда ×5 в `catchFish()`.
|
||||
- Сложность вываживания: `updateReel()`.
|
||||
- Физика боя (спринт 4): `fishForce()` (сила рыбы) и `updateReel()` — drain выносливости, натяжение (`10+…+22·ag`), втягивание `(11+3·reel)·(1+0.6·(1−st))`, свободный бег `F·0.32`, near-miss `1.45·d0`, `d0=45+7·w`. Тесты (§10) завязаны на эти константы — при ребалансе гонять Monte-Carlo точными формулами (docs/PHYSICS-RESEARCH.md, §4.7) и править тесты в том же коммите.
|
||||
- Физика боя (спринт 4): `fishForce()` (сила рыбы: рывок `(16+34·st)·(0.5+0.9·ag)·(0.7+0.5·ov)`, затишье `5+7·ag`, уставшая ×0.45) и `updateReel()` — выносливость `st` (старт `st0`, флаг `tired` при `st≤0.12`: рывки ×0.45, втягивание быстрее до ×1.6), тормоз катушки (черта `drag` в `RODS`: в рывке выше тормоза леска скользит `over·0.22`), натяжение (`10+over·1.1+22·ag`, ×0.35 в затишье), втягивание `(11+3·reel)·(1+0.6·(1−st))`, свободный бег `F·0.32`, escape-бар растёт только при затишье без удержания (отпускание в рывок безопасно), near-miss `1.45·d0`, `d0=45+7·w`. Пустые клёвы: ролл `biteChance()` в ветке WAIT (тест-форс `forceBite`). Тесты (§10) завязаны на эти константы — при ребалансе гонять Monte-Carlo точными формулами (docs/PHYSICS-RESEARCH.md, §4.7) и править тесты в том же коммите.
|
||||
- Награды (M2): шаблоны квестов `QUEST_TPLS`, награды стрика `STREAK_REWARDS`, достижения `ACHIEVEMENTS` — секция «M2. Награды» после сейва.
|
||||
|
||||
## Запуск и публикация
|
||||
|
||||
@@ -12,19 +12,21 @@
|
||||
|
||||
1. **Держи палец** — заряжается мощность броска, **отпусти** — кидаешь удочку. Чем дальше, тем реже, но ценнее рыба.
|
||||
2. Когда поплавок нырнул и появилась **«!**» — быстро нажми экран, чтобы зацепить. У редких рыб окно на подсечку всего доли секунды.
|
||||
3. **Вываживание**: держишь палец — втягиваешь, но растёт нагрузка на шнур (жёлтая полоса справа). Рыба периодически **тянет** (⚡, с вибрацией) — отпусти в этот момент, иначе шнур лопнет. Полоса снизу — оставшаяся дистанция: доведи рыбку до лодки. Чем крупнее рыба, тем сильнее рвёт и дольше тянет.
|
||||
3. **Вываживание**: держишь палец — втягиваешь, но растёт нагрузка на шнур (жёлтая полоса справа). Рыба периодически **тянет** (⚡, с вибрацией) — в этот момент **отпускай**: леска проскальзывает через тормоз катушки, и теряешь только дистанцию. Полоса снизу — оставшаяся дистанция: доведи рыбку до лодки. Чем крупнее рыба, тем сильнее рвёт и дольше тянет. И не зависай без удержания — рыба сойдёт.
|
||||
4. **У каждой рыбы свой вес**, продажа — по цене за кг своего вида (от 20 до 1500 🪙/кг). Крупная рыба = большие деньги.
|
||||
5. **У удочек есть предел веса** (3–40 кг): зацепишь более тяжёлую — шнур лопнет почти мгновенно. Чем лучше удочка и приманка, тем выше шанс зацепить крупную. Новый максимум по виду отмечен бейджем «🏆 РЕКОРД!» на карточке улова.
|
||||
6. На монеты — новые удилища и приманки в магазине 🛒.
|
||||
7. **Награды 🎯**: три квеста дня (уловы, монеты, забросы) с наградой за выполнение; стрик входов — ежедневная награда растёт до дня 7, «щит» прощает один пропуск в неделю; 17 достижений 🏅 с постоянными бонусами (+% к монетам, окно подсечки, нагрузка шнура).
|
||||
8. **День/ночь**: полный цикл суток ~5 минут (утро → день → вечер → ночь). Ночью свой состав рыб — сом, щука и окунь активнее, но без 🪯 фонарика из лавки клёва не будет.
|
||||
9. **Осётр-босс**: при поимке осётра есть шанс встретить босса. Бой идёт в 3 фазы — босс «рвёт и уходит», и каждая следующая фаза глубже; удерживай, чтобы втащить. Награда ×5 к цене.
|
||||
10. **Симулятор боёв (релиз 5)**: у рыбы есть выносливость — тонкая фиолетовая полоска под дистанцией: свежая рыба тянет долго и сильно, а уставшая (💤) вянет — втягивай её именно тогда. У катушек — тормоз (drag): рывок сильнее тормоза — леска скользит. Иногда поплавок не берёт вовсе — пустой клёв, подожди ещё немного.
|
||||
|
||||
## Возможности
|
||||
|
||||
- 8 видов рыб с собственным весом (0.05–40 кг) и ценой за кг (5 уровней редкости)
|
||||
- Удилища: предел веса, прочность шнура, скорость подсечки, бонус на крупную рыбу
|
||||
- Приманки: частота клёва, дальность броска, шанс редких и крупных
|
||||
- Физика боя: выносливость рыбы (уставшая 💤 вянет и втягивается быстрее), тормоз катушки (drag) — сильнейший рывок проскальзывает, пустые клёвы
|
||||
- Цикл дня и ночи (~5 мин на сутки): ночью своя таблица рыб (сом/щука/окунь активнее), без 🪯 фонарика ночью клёва нет
|
||||
- Босс-рыба — Осётр-босс (шанс при поимке осётра): 3 фазы «рвёт и уходит», награда ×5, достижение «Босс-рыбак»
|
||||
- Квесты дня (3 шт, генерация по дню), стрик входов со «щитом», 17 достижений с бонусами
|
||||
@@ -55,7 +57,7 @@ python3 -m http.server 8000
|
||||
```bash
|
||||
cd tests
|
||||
npm install # ставит puppeteer-core
|
||||
node test.js # 54 проверки
|
||||
node test.js # 68 проверок
|
||||
```
|
||||
|
||||
Нужен установленный Chromium (`executablePath` в `test.js` при необходимости поправить).
|
||||
|
||||
@@ -280,3 +280,42 @@ git add -A && git commit -m "что изменилось" && git push
|
||||
| 3 | `commit.gpgsign=true` ронял коммиты воркеров (pinentry некому вводить в headless) | ask от T3 | Коммиты воркеров — `--no-gpg-sign` (локальные ветки, без пуша) |
|
||||
| 4 | Воркер T2 завис на 25 мин: tool-call умер, агент вечно «ждал результатов» | Чекпоинт: замороженный счётчик токенов в TUI | Пинок `terminal send` с инструкцией прервать (esc) и продолжить — рестарт не понадобился |
|
||||
| 5 | Живая игра слишком легка: клёв мгновенный, сходов нет, босс без риска — головой по числам это не видно, только плейтестом | T5: замеры в живом браузере | Баланс числами (см. выше); системно — вываживание и ×5 босса требуют правки логики, оставлено как рекомендации |
|
||||
|
||||
## Этап 15. Спринт 4: симуляторская физика
|
||||
|
||||
**План спринта.** Вываживание из «держалки с таймерами» превратить в перетягивание: у рыбы появляется выносливость, у катушки — тормоз, силы сторон честные, а отпускание в рывке — осознанная стратегия, а не промах. Исследование и план с инвариантами: `docs/PHYSICS-RESEARCH.md` (коммит `fafa0ad`). Поток: T2 — P0-физика (`70ff964`), T3 — независимое ревью с Monte-Carlo (`«к мержу после фиксов»`, 2 MAJOR), T2b — ребаланс по ревью (`60f3755`), T4 — тесты + живой плейтест + замеры ботами (`cc6238a`, вердикт «Релиз готов»), T5 — релиз.
|
||||
|
||||
**Что добавлено (механики по пунктам):**
|
||||
|
||||
1. **Выносливость рыбы (stamina)** — `reel.st`: стартовое `st0 = 0.65+0.35·min(1,w/wMax)` (крупная выносливее), у босса `1` (свежий). Убывает весь бой в `updateReel()`: быстрее в рывке, при удержании и при «сдаче в рывок» (pull без holding). Свежая рыба тянет дольше (рывок `(0.8+2.2·st)·(0.6+0.7·ag)·rand(0.8,1.25)` с), уставшая — короче и слабее: при `st ≤ 0.12` флаг `tired` — сила рывков ×0.45 (`fishForce`), втягивание быстрее до ×1.6. UI: тонкая фиолетовая полоска под дистанцией (затухает к нулю), при усталости — 💤 и статус «💤 Рыба устала — втягивай!»; силуэт уставшей рыбы вялый (амплитуда ×0.35).
|
||||
2. **Тормоз катушки (drag)** — новая черта удилищ в `RODS` (`drag` 34/47/63/87): в рывок сила рыбы `fishForce()` перетягивается против тормоза — если рывок сильнее (`over = F−drag > 0`), леска **скользит** (дистанция растёт `over·0.22`) и нагрузка растёт быстрее; ниже тормоза — нормальное втягивание. UI: отметка drag на жёлтой полосе нагрузки («выше — леска скользит»).
|
||||
3. **Честный баланс сил (T2b)** — сила рыбы `fishForce(r,ag,pull)`: в рывке `(16+34·st)·(0.5+0.9·ag)·(0.7+0.5·ov)`, в затишье `5+7·ag` (уставшая ×0.45); натяжение `10+max(0,over)·1.1+22·ag` (в затишье ×0.35); втягивание `(11+3·reel)·(1+0.6·(1−st))`; свободный бег в рывке `F·0.32`; старт боя `d0 = 45+7·w`; near-miss-порог `1.45·d0` (утешение 10% цены).
|
||||
4. **Escape: отпускать в рывок безопасно** — фикс MAJOR-1: escape-бар больше не растёт при `pull && !holding` (стоимость отпускания — только дистанция, «сдался рыбе»), а растёт только при зависании в затишье без удержания (`0.2+ag·0.4`/с, гашение 0.5/с при holding) — пассивная игра (не держать кнопку) = гарантированный сход. Подсказка «⚡ РЫБА ТЯНЕТ — ОТПУСТИ! ⚡» теперь соответствует механике (MAJOR-2).
|
||||
5. **Пустые клёвы** — поплавок молчит: по таймеру в WAIT ролл `biteChance()` (приманка/дистанция/ночь), промах — новый таймер `rand(2.5,5)/bite`. Тест-форс — глобал `forceBite` (let, паттерн `forceBoss`), сброс — в btnResetYes.
|
||||
|
||||
**Тесты (числа):**
|
||||
|
||||
- `tests/test.js`: +7 проверок (61→**68**): ст-инициализация, ст-убывание, ослабление `fishForce` (F2<0.6·F1), tired-флаг, drag-скольжение (d растёт, tension>drag), drag-втягивание (d падает, tension<drag), пустой клёв. T4: **68/68 PASS ×3 подряд**, exit 0.
|
||||
- `tests/orca-playtest.js`: харденинг против гонки T2b (атомарный hold, см. камешки) — **47/47 live PASS** в браузере Orca, без retry'ев.
|
||||
- `tests/shots.js`: **11/11** кадров, свежие в `screenshots/`.
|
||||
- Monte-Carlo приёмка по точным формулам (N=400/сценарий, dt=1/60, боты доки §4.4): «умный» (держать в calm/отпускать в pull) — карась 98%/13.0 с, окунь 85%, лещ 92%, сом/Карбон 66%/20.4 с, **босс/Титан 59.5%/42.8 с** (босс ≠ 100% даже на топ-удочке); «всегда держать» — мелочь 100%, сом/Стекло 39% + SNAP 61%, босс/Титан 62% + SNAP 38%; «пассив» — 100% сходов за 3.5–6.7 с. Stamina-дуга видна: st при улове 0.2–0.5 против старта 0.7–1.0.
|
||||
|
||||
**Найденные камешки:**
|
||||
|
||||
| # | Камень | Как нашли | Лечение |
|
||||
|---|---|---|---|
|
||||
| 1 | **MAJOR-1 (T3):** skill-curve инвертирован — «правильная» стратегия (держать в calm / отпускать в pull) теряла рыбу: свежий рывок 2.5–3.9 с длиннее escape-окна 1.7–2.3 с (ag≥0.6) → «умный» босс 98–100% сходов; «всегда держать» = 100% уловов впритык и босса на Титане/Карбоне (peakT p90 25–80%); бои 1.3–7.2 с против целей 8–50 с; stamina-дуга не видна | Monte-Carlo (N=400) точных формул из `index.html` с тремя ботами доки §4.4 | Т2b-ребаланс: escape не растёт при `pull&&!holding`, drain медленнее ×~4 (дуга на бой), `d0=45+7·w`, натяжение `10+over·1.1+22·ag`, втягивание `(11+3·reel)·(1+0.6(1−st))`, free-run `F·0.32`; после: босс/Титан 59.5%, бои 10–45 с |
|
||||
| 2 | **MAJOR-2 (T3):** подсказка «⚡ РЫБА ТЯНЕТ — ОТПУСТИ! ⚡» противоречила механике — отпускание в рывок гарантировало «Сбежала!» | Т3-ревью: сопоставление UI-текста с формулами | Лечено вместе с MAJOR-1: отпускание стало безопасным и выигрышным, текст сохранён |
|
||||
| 3 | МИНОР (T3): AGENTS.md не обновлён — новые тест-глобалы `forceBite`/`fishForce` не в списке защищённых имён, счётчик проверок устарел | Т3-чеклист ограничений | Обновление AGENTS.md в коммите T2b (имена в списке, 68 проверок, секция «Физика боя») |
|
||||
| 4 | МИНОР (T3): инвариант доки «втягивание в calm при st=1 = ровно 30·reel px/с» неверен — формула даёт 30 только для rod 0, rod 1–3 медленнее на 17–41% | Сверка доки §4.2 с кодом | Исправлена дока (код — источник истины); учтено в T2b-числах |
|
||||
| 5 | НИТ (T3): полоска stamina перекрывала верх эмодзи ⛵ на HUD | Скриншот `shot-reel.png` | T2b: полоска начинается после эмодзи (dx+18) |
|
||||
| 6 | НИТ (T3): `forceBite`/`forceBoss` не сбрасывались в btnResetYes | Т3-ревью (паттерн предшествовал коммиту) | T2b: сброс добавлен |
|
||||
| 7 | НИТ (T3): тесты §10 завязаны на абсолютные константы физики (запасы 18–80%) | Т3-ревью покрытия | После T2b пороги не упёрлись (запасы ×2.4–×3.1 проверены прогоном); в AGENTS.md — правило гонять Monte-Carlo при ребалансе |
|
||||
| 8 | НИТ (T3): stale `reel` после SNAP/escape/near-miss (не null до следующего hook()) | Т3-аудит утечек состояния | Пререксизинг с main, все потребители под guard'ами `state!=='REEL'` — оставлено как есть |
|
||||
| 9 | Гонка в `orca-playtest.js`: CLI-roundtrip (reset → pointerdown ≈ 1.5–2.5 c игрового времени) длиннее роста escape-бара (1.67 с) — бот «пассивен в затишье» между eval'ами, босс-шаг падал сходом; headless-стресс той же последовательности: 14/60 боёв кончались сходом | T4: прогон 1 упал на босс-шаге (`timeout: SNAP фазы 1, state=WAIT`); диагностика стрессом | Т2b-атомарный hold в тесте: сброс+удержание в ОДНОМ eval, гашение escape-бара в check-eval и при SNAP (паттерн `forceBite`); после: 0/60 в стрессе (даже с гэпом 1.2 с), 47/47 live. Код игры не тронут — хрупок был тест |
|
||||
| 10 | Босс на Титане после подсечки не создаёт угрозы: 20/20 побед, ни одного опасного состояния нагрузки/дистанции (too_easy на адекватной снасти) | T4: живой плейтест + бот (pump, 20 боёв) и трассировки | Не блокер — передано в следующий спринт (усилить рывки/нагрузку на эндгир-удочке или осознанно оставить «наградой за прогресс») |
|
||||
| 11 | 0 настоящих обрывов лески в 259 обычных боёв — ось «прочность шнура» не ощущается игроками-«держателями» | T4: трассировки (макс. нагрузка 80/100) | Не блокер — в следующий спринт (MINOR) |
|
||||
| 12 | 43–47% раннего дохода — утешительные выплаты за сходы (+10% цены): фармить сходы выгоднее осторожной игры (1786 монет за сходы против 953 за уловы) | T4: экономические замеры ботом (~340 забросов) | Не блокер — в следующий спринт (ограничить утешение, напр. только для рыб дороже N) |
|
||||
| 13 | Стартовый клёв p90 13.4 с и ночной простой ~25% суток без фонарика — на границе комфорта первых минут | T4: бот 100 забросов стартовой снастью | Не блокер — в следующий спринт (NIT) |
|
||||
|
||||
**Итог.** Вердикт T4: «Релиз готов» — все рубежи зелёные (68/68 ×3, 47/47 live, 11/11 скриншотов), крашей и pageerror нет, сейв/миграции не трогались (новых персистентных полей нет: `st`/`tired` — поля боя, `drag` — константа RODS, `forceBite` — тест-форс). Балансные находки (камни 10–13) — не блокеры, backlog следующего спринта.
|
||||
|
||||
+2
-1
@@ -747,7 +747,8 @@ const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
await page.mouse.down(); await page.mouse.up(); // подсечка
|
||||
await waitState(page, 'REEL');
|
||||
// ставим рыбу в покой, чтобы escape не мешал, и фиксируем aggr
|
||||
await page.evaluate(() => { reel.phase = 'calm'; reel.phaseT = 9999; reel.holding = false; });
|
||||
// (aggr обязателен: при ag≥0.65 бар заполняется за <2 с и рыба уходит до замера — T5)
|
||||
await page.evaluate(() => { reel.phase = 'calm'; reel.phaseT = 9999; reel.holding = false; reel.aggr = 0.3; reel.escape = 0; });
|
||||
await sleep(100);
|
||||
const escBefore = await page.evaluate(() => reel.escape);
|
||||
await sleep(2000); // 2 с без удержания — escape растёт
|
||||
|
||||
Reference in New Issue
Block a user