Files
fishing-game/docs
andrey 3d7a67c957 Этап 46: Аквариум — сцена коллекции на главном canvas (не локация, баланс не тронут). (1) Данные: save.aqFish[] {id,v,w} + save.aqSlots (старт AQ_BASE_SLOTS=6, макс AQ_MAX_SLOTS=12), AQ_SLOT_COSTS=[1500,4000,9000,20000,45000,100000]; миграция loadSave() — фильтр id по SPECIES, Number.isFinite(w)&&w>0, вариант→'normal', Math.trunc+клампы aqSlots, обрезка хвоста. (2) Модель C: catchFish() не изменён (пины/квесты/ачивки/реклама не тронуты); #btnKeep '🐠 В аквариум' на карточке — бесплатная КОПИЯ (cardSpec/syncKeepBtn, disabled+«Нет места» при лимите), persist+checkAchievements+тост+закрытие+tryInterstitial. (3) Сцена: секция АКВАРИУМ (aqOpen/aqFishRt/aqSel=-1/aqTank), initAquarium/updateAquarium/drawAquarium (вода hexLerp по nightMix, грунт/растения/пузыри, drawFishShape+подкраска варианта AQ_VARIANT_FX/HUE, свечение болотных drawGlowAura), точки frame/draw/onDown(px,py)/resize/syncDom; вход #btnGmAquarium из #gamemenu (openAquarium/closeAquarium, паттерн fromMenuShop), бар #aqBar (#btnAqBack/#aqCount/#btnAqSlot) с pointer-events:none+пилюли auto, поповер #aqPop (вес·редкость, без цены). (4) «Выпустить» #btnAqRelease→aqReleaseSel(): точечное удаление БЕЗ монет/earned/questHit (решение владельца: продажа из банки удалена — закрывает луп ×2 дохода модели C), без телепорта сцены (позиции остальных сохраняются); aqValue() удалён. (5) HUD под сценой: body.aq-open (syncDom+open/close) прячет #hud — клик по #coins/#btnShop из банки невозможен (находка ревью). (6) Слоты: #btnAqSlot по AQ_SLOT_COSTS, sfx('no')+not_enough, disabled на максимуме, гард Number.isFinite(cost). (7) Ачивки 36→38: aq_first 'Первый жилец'/aq_full 'Аквариум полон', обе bonus:{} — пин achBonus().coinPct=0.18 не сдвинут. (8) i18n: gm_aquarium/aq_title/aq_keep/aq_back/aq_slots/aq_buy_slot/aq_max/aq_release/aq_released/aq_no_room/aq_kept (RU/EN), setLang→renderAqBar. (9) Emoji: 🐠 U+1F420 во встроенный субсет (53 глифа, --check OK). (10) Тесты 204→218: блок 'Этап 46' (14 проверок: данные/миграция битых/keep id-v-w/модель C/лимит/сцена вход-выход/слот/выпуск без монет/телепорт), pин a22d 36→38+noCoinBonus. (11) Скриншоты: gen-screenshots.js +кадр aquarium (14→15 × 3 вьюпорта), RU+EN по 45 PNG (EN-набор приведён в синхрон: +swamp/aquarium). (12) Доки: AGENTS.md (пункт 'Аквариум', глобалы, 38 ачивок, 15 кадров, 218 тестов), KODA.md, README.md, DEVLOG (Этап 46), PLAN-AQUARIUM.md (статус 'реализован' + заметка о замене продажи на выпуск). Проверено: 218/218 PASS exit 0, check.mjs OK, emoji --check OK, balance.mjs — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Болото 240.3/328.9 · Море 297.3/476.7 · Океан 329.1/552.7), pack.mjs 5/5 + pack-smoke 6/6, ревью @oracle — все блокирующие находки закрыты.
2026-09-22 21:34:10 +03:00
..
Рыба-босс в каждой локации (Этап 37): BOSS_BY_LOCATION={0:'sturge',1:'crayfish',2:'swordfish',3:'whale'} — босс = существующий вид текущей локации (Осётр/Гигантский рак/Рыба-меч/Синий кит, новых видов в SPECIES нет), условие в startBite() по save.location, тот же паттерн M4 (клон с boss:true, 30% или forceBoss). Единое правило веса: любой босс 20–50 кг (hook(): w=sp.boss?20+rand*30:rollWeight(sp), до d0/ov/st0, тот же w в reel.w/catchFish) — карманного рака нет, но босс до 50 кг > maxW Титана 40: при w>40 в режиме «держи кнопку» возможен настоящий обрыв (вываживается контролем натяжения) — зафиксировано в DEVLOG как материал баланс-этапа. Награда ×5/фазы/карточка «-БОСС» — без изменений, все вид-независимы; старые M4-пины (§9k/§9l(3)/M6(4)) прошли байт-в-байт без правок (награда читает фактический w, фазы нормированы на d0). Ачивки: boss_first — нейтральный текст «Победи рыбу-босса», +3 новые lake_boss 🦞 / sea_boss 🦈 / ocean_boss 🐳 (check по save.bosses[id], БЕЗ coinPct — пин §10c(8) achBonus 0.16 жив; bonus:{} — bonusText/achBonus корректны) — 31→34. save.bosses={} — дефолт save/freshSave + миграция loadSave + запись в boss-ветке catchFish. Тесты: новый блок §9k2 (3 локации × старт/вес 20–50 по фактическому reel.w/улов ×5/save.bosses/ачивка/карточка) + миграция сейва, a22d 31→34 — 193/193 PASS (2 прогона); check.mjs OK; emoji-font --check OK (🦞/🦈/🐳 уже в субсете); balance.mjs — без сдвига (босс вне ролла). Доки: README/AGENTS/KODA/DEVLOG (Этап 37), BROWSER-TESTING и orca-playtest — цифры босса 5–40→20–50 кг.
2026-09-19 21:31:54 +03:00
Этап 46: Аквариум — сцена коллекции на главном canvas (не локация, баланс не тронут). (1) Данные: save.aqFish[] {id,v,w} + save.aqSlots (старт AQ_BASE_SLOTS=6, макс AQ_MAX_SLOTS=12), AQ_SLOT_COSTS=[1500,4000,9000,20000,45000,100000]; миграция loadSave() — фильтр id по SPECIES, Number.isFinite(w)&&w>0, вариант→'normal', Math.trunc+клампы aqSlots, обрезка хвоста. (2) Модель C: catchFish() не изменён (пины/квесты/ачивки/реклама не тронуты); #btnKeep '🐠 В аквариум' на карточке — бесплатная КОПИЯ (cardSpec/syncKeepBtn, disabled+«Нет места» при лимите), persist+checkAchievements+тост+закрытие+tryInterstitial. (3) Сцена: секция АКВАРИУМ (aqOpen/aqFishRt/aqSel=-1/aqTank), initAquarium/updateAquarium/drawAquarium (вода hexLerp по nightMix, грунт/растения/пузыри, drawFishShape+подкраска варианта AQ_VARIANT_FX/HUE, свечение болотных drawGlowAura), точки frame/draw/onDown(px,py)/resize/syncDom; вход #btnGmAquarium из #gamemenu (openAquarium/closeAquarium, паттерн fromMenuShop), бар #aqBar (#btnAqBack/#aqCount/#btnAqSlot) с pointer-events:none+пилюли auto, поповер #aqPop (вес·редкость, без цены). (4) «Выпустить» #btnAqRelease→aqReleaseSel(): точечное удаление БЕЗ монет/earned/questHit (решение владельца: продажа из банки удалена — закрывает луп ×2 дохода модели C), без телепорта сцены (позиции остальных сохраняются); aqValue() удалён. (5) HUD под сценой: body.aq-open (syncDom+open/close) прячет #hud — клик по #coins/#btnShop из банки невозможен (находка ревью). (6) Слоты: #btnAqSlot по AQ_SLOT_COSTS, sfx('no')+not_enough, disabled на максимуме, гард Number.isFinite(cost). (7) Ачивки 36→38: aq_first 'Первый жилец'/aq_full 'Аквариум полон', обе bonus:{} — пин achBonus().coinPct=0.18 не сдвинут. (8) i18n: gm_aquarium/aq_title/aq_keep/aq_back/aq_slots/aq_buy_slot/aq_max/aq_release/aq_released/aq_no_room/aq_kept (RU/EN), setLang→renderAqBar. (9) Emoji: 🐠 U+1F420 во встроенный субсет (53 глифа, --check OK). (10) Тесты 204→218: блок 'Этап 46' (14 проверок: данные/миграция битых/keep id-v-w/модель C/лимит/сцена вход-выход/слот/выпуск без монет/телепорт), pин a22d 36→38+noCoinBonus. (11) Скриншоты: gen-screenshots.js +кадр aquarium (14→15 × 3 вьюпорта), RU+EN по 45 PNG (EN-набор приведён в синхрон: +swamp/aquarium). (12) Доки: AGENTS.md (пункт 'Аквариум', глобалы, 38 ачивок, 15 кадров, 218 тестов), KODA.md, README.md, DEVLOG (Этап 46), PLAN-AQUARIUM.md (статус 'реализован' + заметка о замене продажи на выпуск). Проверено: 218/218 PASS exit 0, check.mjs OK, emoji --check OK, balance.mjs — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Болото 240.3/328.9 · Море 297.3/476.7 · Океан 329.1/552.7), pack.mjs 5/5 + pack-smoke 6/6, ревью @oracle — все блокирующие находки закрыты.
2026-09-22 21:34:10 +03:00
Экономика: ушедшие рыбы без наград — выплаты 10% цены убраны из обеих веток схода в updateReel() (escape>=1 и near-miss 1.45·d0), общий хвост вынесен в fishEscaped() (тост «Сбежала! <emoji> <имя> <вес> кг» → WAIT → biteTimer → sfx('escape')), устаревший near-miss-комментарий удалён; формат сейва не менялся. Тост обрыва: теперь с рыбой («💥 Линия лопнула! 🐟 Карась 0.5 кг» / «💥 Рыба крупнее предела удочки! …», разбор ov>1.15 сохранён); босс-обрыв фазы не тронут. Закрывает камень #12 из Этапа T4 (утешения за сходы = 43–47% раннего дохода, фармить сходы было выгоднее). Тесты: §9c переписан (пин save.quests/стрика — монеты не изменились; тост «Сбежала!» с весом без «🪙»), (2b) переиспользован (сход монет не даёт, HUD в согласии с сейвом), +1 чек тоста обрыва (чтение в следующем eval сразу после waitState('SNAP'): тост 1.6 с > SNAP 1.0 с); orca шаг 9 — «сход без выплат». 129/129, exit 0; Orca 61/61 live. Доки: DEVLOG Этап 23, PHYSICS-RESEARCH исходы, README/AGENTS 128→129.
2026-09-07 13:15:28 +03:00
Этап 46: Аквариум — сцена коллекции на главном canvas (не локация, баланс не тронут). (1) Данные: save.aqFish[] {id,v,w} + save.aqSlots (старт AQ_BASE_SLOTS=6, макс AQ_MAX_SLOTS=12), AQ_SLOT_COSTS=[1500,4000,9000,20000,45000,100000]; миграция loadSave() — фильтр id по SPECIES, Number.isFinite(w)&&w>0, вариант→'normal', Math.trunc+клампы aqSlots, обрезка хвоста. (2) Модель C: catchFish() не изменён (пины/квесты/ачивки/реклама не тронуты); #btnKeep '🐠 В аквариум' на карточке — бесплатная КОПИЯ (cardSpec/syncKeepBtn, disabled+«Нет места» при лимите), persist+checkAchievements+тост+закрытие+tryInterstitial. (3) Сцена: секция АКВАРИУМ (aqOpen/aqFishRt/aqSel=-1/aqTank), initAquarium/updateAquarium/drawAquarium (вода hexLerp по nightMix, грунт/растения/пузыри, drawFishShape+подкраска варианта AQ_VARIANT_FX/HUE, свечение болотных drawGlowAura), точки frame/draw/onDown(px,py)/resize/syncDom; вход #btnGmAquarium из #gamemenu (openAquarium/closeAquarium, паттерн fromMenuShop), бар #aqBar (#btnAqBack/#aqCount/#btnAqSlot) с pointer-events:none+пилюли auto, поповер #aqPop (вес·редкость, без цены). (4) «Выпустить» #btnAqRelease→aqReleaseSel(): точечное удаление БЕЗ монет/earned/questHit (решение владельца: продажа из банки удалена — закрывает луп ×2 дохода модели C), без телепорта сцены (позиции остальных сохраняются); aqValue() удалён. (5) HUD под сценой: body.aq-open (syncDom+open/close) прячет #hud — клик по #coins/#btnShop из банки невозможен (находка ревью). (6) Слоты: #btnAqSlot по AQ_SLOT_COSTS, sfx('no')+not_enough, disabled на максимуме, гард Number.isFinite(cost). (7) Ачивки 36→38: aq_first 'Первый жилец'/aq_full 'Аквариум полон', обе bonus:{} — пин achBonus().coinPct=0.18 не сдвинут. (8) i18n: gm_aquarium/aq_title/aq_keep/aq_back/aq_slots/aq_buy_slot/aq_max/aq_release/aq_released/aq_no_room/aq_kept (RU/EN), setLang→renderAqBar. (9) Emoji: 🐠 U+1F420 во встроенный субсет (53 глифа, --check OK). (10) Тесты 204→218: блок 'Этап 46' (14 проверок: данные/миграция битых/keep id-v-w/модель C/лимит/сцена вход-выход/слот/выпуск без монет/телепорт), pин a22d 36→38+noCoinBonus. (11) Скриншоты: gen-screenshots.js +кадр aquarium (14→15 × 3 вьюпорта), RU+EN по 45 PNG (EN-набор приведён в синхрон: +swamp/aquarium). (12) Доки: AGENTS.md (пункт 'Аквариум', глобалы, 38 ачивок, 15 кадров, 218 тестов), KODA.md, README.md, DEVLOG (Этап 46), PLAN-AQUARIUM.md (статус 'реализован' + заметка о замене продажи на выпуск). Проверено: 218/218 PASS exit 0, check.mjs OK, emoji --check OK, balance.mjs — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Болото 240.3/328.9 · Море 297.3/476.7 · Океан 329.1/552.7), pack.mjs 5/5 + pack-smoke 6/6, ревью @oracle — все блокирующие находки закрыты.
2026-09-22 21:34:10 +03:00
Этап 45: локация «Волшебное болото» (id 4, 90 000 🪙) — светящиеся рыбы, лягушки, кувшинки/лилии. (1) Данные: LOCATIONS[4] (тёмно-моховая вода 6 hex, слабая рябь; в массиве ПОСЛЕДНИЙ, по цене — между Озёрами 65536 и Морем 131072); 5 новых видов строго в КОНЕЦ SPECIES (32→37, по одному на редкость r0–r4, у каждого glow:'#hex' — 5 разных цветов): glowfin Светлячок #5ff2ff 8🪙, moonfish Лунная рыбка #b9c8ff 13, emberfin Изумрудный светляк #57ffa8 20, violetlure Фиалковый огонёк #d17bff 38, spiritfin Дух болота #ffe07a 70; SWAMP_IDS/SWAMP_DAY_WEIGHTS/SWAMP_NIGHT_WEIGHTS/SWAMP_SPECIES(_NIGHT) — паттерн LAKE/SEA/OCEAN без пересечений; NIGHT_WEIGHTS — ключи всем 37 id. (2) pickSpecies(): вложенный тернарник → табличный доступ SPECIES_BY_LOCATION(_NIGHT) по save.location + guard (вне 0..4 → Река); роллы 0..3 бит-в-идентичны (lc3/lc4/lc4b/lc4c + речные §9j/M4/M6 не тронуты). (3) Свечение (только ночь): nightMix()>0.35 — тот же порог, что у фонаря; drawGlowAura() (радиальный градиент + 'lighter', save/restore, кэш GLOW_RGBA) — фоновые рыбы болота (AMBIENT_FISH[4] — 7 рыб + palette из 4 цветов, цвет стабильно по индексу), зацепившаяся/вываживаемая (fishGlow — вид с glow), боссовая золотая аура сохранена; карточка — класс glow-card + --glow (только normal-вариант, drop-shadow, не конфликтует с фильтрами вариантов), дневник — drop-shadow на SVG. (4) Декорации: initScenery() ветка i===4 (bank+reed+snag+pine в болотной гамме), ГЛОБАЛЬНЫЕ pads[] (8–14 кувшинок с вырезом, 45% с лилиями — жёлтые/белые/розовые) и frogs[] (3–5, sit→jump по параболе на соседнюю кувшинку, 3–7 с) — очищаются/пересобираются в initScenery() (resize + обе ветки shopClick); updateDecor(dt) — покачивание/прыжки; drawSwampDecor() — ОТДЕЛЬНЫЙ слой после drawWater/drawAmbientFish и до drawBoat (дusk берега не гасит; локальное притухание ночью). (5) Босс: BOSS_BY_LOCATION[4]='spiritfin' (Дух болота, 20–50 кг, ×5 — паттерн Этапа 37). (6) Магазин/i18n/ачивки: тост welcome_swamp (ru/en, тернарник → if/else), ачивки 34→36: swamp_first (bonus:{coinPct:0.02}, locations-based) + swamp_boss (bonus:{}, bosses.spiritfin) → пин achBonus().coinPct 0.16→0.18; species_8 = все 37. (7) Баланс: SWAMP_DAY_WEIGHTS {glowfin:3,moonfish:4,emberfin:28,violetlure:13,spiritfin:4.5}, SWAMP_NIGHT_WEIGHTS {glowfin:2.5,moonfish:2.5,emberfin:20,violetlure:30,spiritfin:4} — Болото 240.3/328.9 🪙 (ночь/день ×1.37), порядок по цене Озёра 194.1/249.0 < Болото < Море 297.3/476.7 в ОБЕ фазы; пины остальных вод не изменились (Река 65.1/125.9 · Озёра 194.1/249.0 · Море 297.3/476.7 · Океан 329.1/552.7). (8) tools/balance.mjs: 8→10 таблиц, +SWAMP_SPECIES(_NIGHT) в return, сводка/пары отношений — сортировка ПО ЦЕНЕ (болото встает между Озёрами и Морем), пины в шапке. (9) Портреты: 5 flat-SVG (каждый — отдельным художником) assets/fish/fish-{glowfin,moonfish,emberfin,violetlure,spiritfin}.svg (viewBox 0 0 160 100, var(--f1..f4,hsl-fallback)); embed-fish.mjs IDS 32→37 (в конец), 37 <symbol> в index.html; fish-preview.html 32→37 карточек. (10) Тесты (тот же коммит): lc1 (37/5 локаций/90000/names/sprites 37/oceanOrder slice(23,32)/swampOrder/swampGlow/swampRar), lc2 (+SWAMP-таблицы, пересечения, nightW 37), lc4d (новый: 3000+3000 роллов болота — все 5 ≥1, чужих нет), lc5 (+location:4 не сбрасывается, location:5→0), lc8w (новый: покупка 90000 + welcome_swamp), lc9 (37), lc10 (mid29), lc11 (новый: glow #rrggbb, 5 цветов различны, веса покрывают id, NIGHT_WEIGHTS — все 37), a22d (36), a36loc (+swamp_first), пин 0.18, §9k2 (+{loc:4, spiritfin, swamp_boss}). 198→204 PASS, exit 0. (11) Скриншоты: gen-screenshots.js +кадры swamp/swamp-night (12→14 × 3 вьюпорта, dayTime 0.3/0.85) — 42 RU + 42 EN PNG (screenshots-wiki/, screenshots-wiki-en/). (12) Доки: AGENTS.md (локации/босс/баланс/баланс-скрипт/награды/портреты/скриншоты), README (5 локаций, 37 видов, 36 ачивок, 204 теста, 14 кадров, mobp-swamp*), KODA.md (SWAMP_*, SPECIES_BY_LOCATION, drawGlowAura/fishGlow/GLOW_RGBA, drawSwampDecor, pads/frogs), DEVLOG (Этап 45), PLAN-SWAMP.md (статус «реализован»). Проверено: 204/204 PASS exit 0, check.mjs OK, balance.mjs — пины без изменений + Болото в цели, emoji-font --check OK (52 глифа, новых emoji нет), ревью @oracle — критичных замечаний нет (.gitignore + .opencode/, fish-preview, осколок комментария species_8 — закрыты в этом же коммите). Миграция сейва не тронута (граница из LOCATIONS.length; location=4 покрыт lc5(f)).
2026-09-21 22:59:15 +03:00