Доходность Озёр 100+ 🪙 (Этап 34): LAKE_*_WEIGHTS — сдвиг долей в пользу дорогой рыбы, день 84.7→110.4 (×1.70 реки), ночь 122.2→145.5 (×1.16 реки).

Пользователь предлагал «просто увеличить вес озёрных рыб», но pickSpecies() нормирует веса (шанс = w/total из тех же w), поэтому ожидаемая выручка за улов = Σ(w·V)/Σw (V — середина диапазона веса × цена) инвариантна к умножению всех весов на константу: масштабирование дало бы ровно те же 84.7. Заявленный эффект достигнут тем же инструментом — правкой двух озёрных таблиц, но сдвигом ДОЛЕЙ: вниз размыватели carass 60→55 (V≈9 🪙, был 21% всех роллов) и bleak 30→18 (V≈6), плюс bream 30→24, perch 40→36, chuch 22→18, roundel 18→12, carp 25→24; вверх дорогая рыба — sturge 3.5→5, gold 1.6→2.2, tench 10→14, catfish 8→10, navaga 2.5→3.4, zander 14→16, pike 12→14, crayfish 2→2.4.

Попутно исправлено расхождение, которое комментировалось как норма: ночью Озёра были УБЫТОЧНЕЕ ночи Реки (122.2 < 125.9) при «смещении к хищникам». Ночная таблица выправлена в том же направлении — perch 70→60, carass 25→22, bream/chuch 10→9, tench 8→11, zander 18→20, catfish 16→18, sturge 4.5→6, gold 1.6→2.2, crayfish 2.5→2.6, navaga 2→2.4. Река не тронута (RIVER_IDS, weight в SPECIES, NIGHT_WEIGHTS) — роллы реки прежние, pin lc3 цел.

Пол редких видов не тронут вниз: минимальный вес 2.2 (gold/navaga/crayfish) — за 3000 роллов ожидается ≥25 попаданий против ~20 у gold раньше, так что lc4 («каждый вид ≥1», где из-за отсутствия аргумента не действует штраф minDist) проходит с вероятностью провала ~e⁻²⁵ вместо прежнего меньшего запаса. Ниже ~2 в этих таблицах опускать нельзя — зафиксировано в AGENTS.md/KODA.md.

Тесты: конкретных значений озёрных весов пинов нет (lc2 — длина 16 и «вес — число», lc4 — факт выпадения), правка таблиц не потребовала правок тестов: 178/178 PASS, exit 0; check.mjs OK; pack.mjs + pack-smoke 6/6 (115.5 КБ). Скриншоты не перегенерированы осознанно: кадры рила и карточки форсируют sturge в gen-screenshots.js, остальные от весов не зависят.

Доки: DEVLOG — «Этап 34» (инвариантность к масштабу, полный список весов, ночное расхождение, пол 2.2), AGENTS.md и KODA.md — правило «дороже = сдвиг долей, а не масштаб» + текущие ориентиры Озёра 110.4/145.5 против Реки 65.1/125.9 и минимальный вес ~2.2; README — Озёра «улов в ~1.2–1.7 раза доходнее Реки».
This commit is contained in:
2026-09-18 20:10:15 +03:00
parent aace2b130a
commit 812c65bd90
4 changed files with 26 additions and 4 deletions
+1
View File
@@ -40,6 +40,7 @@
- Погода (M8): таблица `WEATHER` (rain — `variantMult` ×3; fog — `biteMult` ×1,5), таймеры в реальном времени — `updateWeather()` в `frame()` (gap `WEATHER_GAP_MIN..MAX` 120–240 с, длительность `WEATHER_DURATION` 120 с, под форсом не гоняются), `weatherActive()` — единственная точка чтения (форс приоритетнее), эффекты только в `variantChance()` (rain) и `biteChance()` (fog), тест-форс `forceWeather` ('rain'/'fog'/null, паттерн `forceBoss`); погода не персистится в сейв. Тост погоды — из `T` (`t('wx_'+weather)`; `WEATHER.*.toast` — не используется). Заметка: туман может дать p&gt;1 → насыщение 100% клёва (осознанно).
- Скины (M-skins): таблицы `BOAT_SKINS`/`BOBBER_SKINS` (лодка: Обычная 0 / «Красная лодка» 800 / «Лодка-домик» 2000 🪙; поплавок: Обычный 0 / Красный 500 / Неоновый 1500 🪙), сейв `save.boatSkin(s)`/`save.bobberSkin(s)` + миграция в `loadSave()` (включая гарантию бесплатного скина 0), вкладка «Скины» 🎨 (`#tabSkins`, строка `skinRow(list,i,owned,equipped,group)`, ветки buyskin/select в `shopClick()`: покупка со списанием и авто-экипировкой, выбор — только купленное), отрисовка `drawBoat()`/`drawBobber()` с clamp 0..2 (скин 2: каюта у лодки, неоновое свечение `shadowBlur` в save/restore у поплавка); чистая косметика — без эффектов на геймплей.
- Локации (этап 5): таблица `LOCATIONS` (Река 0 — бесплатно / «Озёра» 100000 🪙; `water` — 6 hex [dayTop,dayMid,dayBot,nightTop,nightMid,nightBot] для градиента `drawWater()`, nightMix-логика та же), сейв `save.locations[]`/`save.location` + миграция в `loadSave()` (гарантия бесплатной Реки, паттерн скинов), вкладка «Локации» 🗺️ (`#tabLocations`, строка `locationRow(loc,i,owned,selected)`, ветки buylocation/selectlocation в `shopClick()`: покупка — списание, push, АВТО-ПЕРЕХОД `save.location`, тост «Добро пожаловать на Озёра!»; выбор — только купленное). Таблицы рыб: `RIVER_SPECIES(_NIGHT)` — ТОЛЬКО 8 базовых видов (роллы реки не меняются: pin-тесты §9j(b)/M4/M6 завязаны на веса и порядок — новые виды в реку НЕ добавлять!), `LAKE_SPECIES(_NIGHT)` — все 16 видов (веса `LAKE_DAY_WEIGHTS`/`LAKE_NIGHT_WEIGHTS`); `SPECIES`/`SPECIES_NIGHT` — полный словарь 16 видов (этап 5: zander/chuch/crayfish, этап 33: bleak/roundel/eelpout/tench/navaga; ночные веса — в `NIGHT_WEIGHTS`, ключ обязателен каждому id, иначе `weight=undefined`). **Новые виды добавлять только в КОНЕЦ `SPECIES`** — `SPECIES[0..7]` запинены тестами (§573/§1524/§2446 `SPECIES[0]`, §9j/M4/M6 по id) и квестами (`QUEST_TPLS` индексы 0..2); вставка в середину молча сломает их. `pickSpecies()` выбирает таблицу по `save.location` и dayPhase (логика ролла та же); босс (sturge) есть в обеих локациях; ачивка species_8 — «Поймай все виды» (все 16, check = `SPECIES.every`, id не менять — старые сейвы).
- **Баланс Озёр (этап 34):** ожидаемая выручка за улов = Σ(w·V)/Σw, V — середина диапазона веса × цена. `pickSpecies()` нормирует веса, так что **умножение всех весов на константу доход НЕ меняет** — для «стало дороже» правят СДВИГ долей (меньше `carass`/`bleak` — самые дешёвые V≈9/6 🪙, больше `sturge`/`gold`/`catfish`/`tench`/`navaga`). Текущие ориентиры: Озёра день 110.4 / ночь 145.5 🪙, Река день 65.1 / ночь 125.9 (Озёра доходнее в обе фазы — проверять при любой правке `LAKE_*_WEIGHTS`). **Минимальный вес вида ≥ ~2.2**: ниже — тест lc4 (3000 роллов, «каждый вид ≥1») начинает плавать.
- Сложность вываживания: `updateReel()`.
- Физика боя (спринт 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. Награды» после сейва. Этап 22: ачивок 29 (идут `ACHIEVEMENTS`-записями по темам: снасти у экономики, варианты/погода/вес/ночь у рыболовных, скины/локации у магазинных); новые счётчики сейва `save.kgTotal`/`nightCatch`/`wxRainV`/`wxFog` (чтение через `||0` — без миграции) ставятся в `catchFish()` до `checkAchievements()` (rain-счётчик — только вариант ≠ normal, босс всегда normal); тест-пин §10c(8): сумма `achBonus().coinPct` (все 8 видов × 8 вариантов) = 0.16.
+1 -1
View File
@@ -33,7 +33,7 @@
- Варианты рыб (особая рыба ≈31%): медная ×1.5, серебряная ×2, кварцевая ×2.5, золотая ×3, изумрудная ×4, алмазная ×4.5, радужная ×5 (топ, самая редкая) — бейдж и оформление карточки улова; снасть усиливает шанс (тип наживки и её уровень — редким вариантам прибавка больше, топ-снасть ≈×5 к шансу радужной)
- Погода: дождь (🌧️) — шанс особых рыб ×3; туман (🌫️) — клёв ×1,5; событие идёт 120 с, следующее — раз в 2–4 минуты — <img src="screenshots-wiki/mobp-weather-rain.png" width="200" alt="дождь">
- Скины лодки и поплавка 🎨 — вкладка «Скины» в лавке: лодка «Красная лодка» 800 🪙 / «Лодка-домик» 2000 🪙, поплавок «Красный» 500 🪙 / «Неоновый» 1500 🪙 — чистая косметика (без эффектов на геймплей)
- Локации: Озёра (100 000 🪙) — судак, хариус, гигантский рак; свой состав днём/ночью, свой цвет воды; покупка и переключение во вкладке 🗺️ лавки — <img src="screenshots-wiki/mobp-lake.png" width="200" alt="озёра">
- Локации: Озёра (100 000 🪙) — судак, хариус, гигантский рак; свой состав днём/ночью, свой цвет воды, улов в ~1.2–1.7 раза доходнее Реки; покупка и переключение во вкладке 🗺️ лавки — <img src="screenshots-wiki/mobp-lake.png" width="200" alt="озёра">
- Квесты дня (3 шт, генерация по дню), стрик входов со «щитом», 29 достижений с бонусами
- Дневник рыбака — коллекция, максимальный улов по каждому виду, статистика
- Магазин с вкладками: Лавка 🛒, Дневник 📔, Награды 🎯, Достижения 🏅, Скины 🎨, Локации 🗺️
+13
View File
@@ -643,3 +643,16 @@ git add -A && git commit -m "что изменилось" && git push
**Тесты:** lc1 — `SPECIES.length` 11→16, пины параметров пяти новых видов, порядок (`slice(0,8)` не сдвинут, `slice(8)` — ровно 8 озёрных) и заполненность всех полей (включая `nameEn` — иначе EN-ветка `trName()`); lc2 — `LAKE_SPECIES(_NIGHT)` 11→16, `SPECIES_NIGHT.length` 16 + веса числа; lc3 — без изменений (Река = старые 8); lc4 — текстовка «все 16» (состав берётся из `SPECIES.map`, подстраивается сам); lc9 — строк дневника 11→16; lc10 — сетап «+3 новых» → «+8 озёрных». Итого **178/178 PASS, exit 0**.
**Флейка, которую стоит помнить:** lc4 вызывает `pickSpecies()` **без аргумента** → `dist = undefined`, `undefined < s.minDist` === false, штраф ×0.06 не применяется. На «каждый вид ≥1 за 3000 роллов» влияет **только вес** — новому озёрному виду нужен вес ≥ ~2 в обеих озёрных таблицах (у navaga 2.5 / 2).
## Этап 34. Доходность Озёр 100+ 🪙 (веса)
**Задача:** «для озёр доходность желательно 100+, предлагаю просто увеличить вес рыб озёрных».
**Решения:**
- **Масштаб весов доход не меняет.** `pickSpecies()` нормирует веса (шанс = `w / total`, где `total` — сумма тех же `w`), поэтому ожидаемая выручка за улов (середина диапазона веса × цена, взвешенная по вероятностям) инвариантна к умножению ВСЕХ весов на константу: «просто увеличить все веса» дало бы ровно те же 84.7 🪙. Поднят **сдвиг долей** в пользу дорогой рыбы — заявленный эффект достигнут тем же инструментом (правкой `LAKE_*_WEIGHTS`).
- **Убраны размыватели, поднята дорогая рыба (день):** `carass` 60→55 (выручка ≈9 🪙, был 21% всех роллов) и `bleak` 30→18 (≈6 🪙) — главные «копейки» Озёр; вверх `zander` 14→16, `catfish` 8→10, `pike` 12→14, `tench` 10→14, `navaga` 2.5→3.4, `sturge` 3.5→**5**, `gold` 1.6→**2.2**, `crayfish` 2→2.4; вниз `bream` 30→24, `perch` 40→36, `chuch` 22→18, `roundel` 18→12, `carp` 25→24.
- **Ночь Озёр была убыточнее ночи Реки** (122.2 против 125.9 🪙) — вопреки комментарию про «ночное смещение к хищникам». Исправлена тем же сдвигом: `perch` 70→60, `carass` 25→22, `bream`/`chuch` 10→9, `tench` 8→11, `zander` 18→20, `catfish` 16→18, `sturge` 4.5→**6**, `gold` 1.6→**2.2**, `crayfish` 2.5→2.6, `navaga` 2→2.4.
- **Итог:** Озёра **день 84.7 → 110.4** 🪙 (×1.70 к дневному руслу реки 65.1), **ночь 122.2 → 145.5** (×1.16 к ночной реке 125.9). Река не тронута (`RIVER_IDS`, `SPECIES.weight`, `NIGHT_WEIGHTS`).
- **Пол редких видов сохранён:** минимальный вес 2.2 (`gold`/`navaga`/`crayfish`) — за 3000 роллов ожидается ≥25 попаданий (у `gold` раньше было ~20). Тест lc4 («каждый вид ≥1») проходит с вероятностью провала ~e⁻²⁵; ниже ~2 опускать нельзя (флейка выше: штраф `minDist` в тесте не действует).
**Тесты:** конкретных значений озёрных весов никто не пинит (lc2 — только длина 16 и «вес — число», lc4 — факт выпадения всех видов), правка таблиц не потребовала правок тестов: **178/178 PASS, exit 0**; `check.mjs` OK; `pack.mjs` + `pack-smoke` 6/6 (115.5 КБ). Скриншоты перегенерированы не нужны: кадр рила и карточка форсируют `sturge` в `gen-screenshots.js`, остальные кадры от весов не зависят.
+11 -3
View File
@@ -404,9 +404,17 @@ const RIVER_SPECIES_NIGHT=SPECIES_NIGHT.filter(s=>RIVER_IDS.indexOf(s.id)>=0);
LAKE_NIGHT_WEIGHTS — правьте ночные озёра здесь.
Этап 33: +пять новых видов (bleak/roundel/eelpout/tench/navaga) и подъём дорогой рыбы
(gold 1.2→1.6, sturge 3→3.5/4.5, crayfish 1.5→2/2.5) — иначе мелочь размывает доход Озёр:
E[выручка/улов] 91.9→73.5 🪙, с подъёмом 84.7 (Река для сравнения 65.1) */
const LAKE_DAY_WEIGHTS={carass:60,perch:40,bream:30,carp:25,zander:14,chuch:22,pike:12,catfish:8,crayfish:2,sturge:3.5,gold:1.6,bleak:30,roundel:18,eelpout:6,tench:10,navaga:2.5};
const LAKE_NIGHT_WEIGHTS={carass:25,perch:70,bream:10,carp:8,zander:18,chuch:10,pike:24,catfish:16,crayfish:2.5,sturge:4.5,gold:1.6,bleak:14,roundel:10,eelpout:12,tench:8,navaga:2};
E[выручка/улов] 91.9→73.5 🪙, с подъёмом 84.7 (Река для сравнения 65.1).
Этап 34: доход Озёр поднят до 100+ 🪙. Средневзвешенный доход Σ(w·V)/Σw НЕ зависит от
общего масштаба весов — «увеличить все веса» дохода не даёт, поэтому поднят именно
СДВИГ ДОЛЬ в пользу дорогой рыбы: carass 60→55 и bleak 30→18 (главные размыватели,
V=9 и 6 🪙), carp/zander/pike/catfish/tench вверх, sturge 3.5→5/6, gold 1.6→2.2.
Стало день 110.4 (×1.70 дневной реки 65.1), ночь 145.5 (×1.16 ночной реки 125.9);
раньше ночью Озёра были УБЫТОЧНЕЕ ночи Реки (122.2 < 125.9) — исправлено.
Пол редких видов: минимальный вес 2.2 (gold/navaga/crayfish) — за 3000 роллов ожидается
≥25 попаданий, тест lc4 («каждый вид ≥1») проходит с огромным запасом */
const LAKE_DAY_WEIGHTS={carass:55,perch:36,bream:24,carp:24,zander:16,chuch:18,pike:14,catfish:10,crayfish:2.4,sturge:5,gold:2.2,bleak:18,roundel:12,eelpout:6,tench:14,navaga:3.4};
const LAKE_NIGHT_WEIGHTS={carass:22,perch:60,bream:9,carp:9,zander:20,chuch:9,pike:24,catfish:18,crayfish:2.6,sturge:6,gold:2.2,bleak:12,roundel:9,eelpout:12,tench:11,navaga:2.4};
const LAKE_SPECIES=SPECIES.map(s=>Object.assign({},s,{weight:LAKE_DAY_WEIGHTS[s.id]}));
const LAKE_SPECIES_NIGHT=SPECIES.map(s=>Object.assign({},s,{weight:LAKE_NIGHT_WEIGHTS[s.id]}));