diff --git a/AI_MAP.md b/AI_MAP.md index ace542d..c1759d3 100644 --- a/AI_MAP.md +++ b/AI_MAP.md @@ -96,10 +96,17 @@ This section records current boundaries only. Version-by-version cleanup history - Hair Trigger preset: `js/world_reset_presets.js`; physics tool icon renderer: `js/ui_tools.js`; world tooltip offset: `js/render.js`. -## Achievement system (v39.16.56) -- `js/achievements.js`: 51 definitions, local unlock state, persistent placement/ant-kill/reproduction/fight/Undo/Redo/quick-delete progress, field-scoped direct-feed/cleaner/self-sufficiency/enemy-ant progress, individual care/hold/temperature/fight markers, allowlisted inline disclosures and local progress, shared-rate bars/counts, event-driven generation/status-effect/first-aid/plushie checks, completionist chaining, cached hidden-dialog rendering, debounced pending synchronization, and periodic additive full-state recovery synchronization. +## Achievement system (v39.16.60) +- `js/achievements.js`: 54 definitions, local unlock state, persistent placement/ant-kill/reproduction/fight-mochi/shot/love-mochi/Undo/Redo/quick-delete progress, field-scoped direct-feed/cleaner/self-sufficiency/enemy-ant progress, individual care/hold/temperature/fight markers, allowlisted inline disclosures and local progress, shared-rate bars/counts, event-driven generation/status-effect/first-aid/plushie checks, completionist chaining, cached hidden-dialog rendering, debounced pending synchronization, and periodic additive full-state recovery synchronization. - `achievement_api.php`: validates current IDs, reads legacy verbose or compact v2 aggregate state, writes compact indexed arrays, migrates the intersection of the retired automation/link achievements into `mechanized_industry`, accepts idempotent bulk unlock synchronization, and returns anonymous global percentages plus achiever counts. - `css/components.css`: achievement rows use `--achievement-rate` to render horizontal background fills; unlocked rows use a distinct fill. -- `js/world.js`, `js/snapshot_system.js`, and `js/save_codec.js`: field-local achievement counters and per-entity/item markers reset with a new field and persist within current-format saves; the current save schema intentionally has no backward compatibility. +- `js/world.js`, `js/snapshot_system.js`, and `js/save_codec.js`: field-local achievement counters and per-entity/item markers reset with a new field and persist within current-format saves; schema 43 is current; compact schema 42 and legacy JSON schema 41 remain readable for migration. - Hooks span placement/deletion/history, robot cleaning, direct care and consumables, fight starts/deaths, ant damage attribution, save slots, pause input, hold state, population/temperature/weather evaluation, first-aid recovery, shared poke targeting/highlights, plushie fling, and nest-box/pipe weather blocking. -- Audits: `scripts/achievement_audit.js` checks legacy/current boundaries and recovery; `scripts/playstyle_achievement_audit.js` checks the play-style conditions, reset scopes, false-positive guards, tooltips, and production hooks; `scripts/achievement_integration_audit.py` checks IDs and integration wiring. \ No newline at end of file +- Audits: `scripts/achievement_audit.js` checks legacy/current boundaries and recovery; `scripts/playstyle_achievement_audit.js` checks the play-style conditions, reset scopes, false-positive guards, tooltips, and production hooks; `scripts/achievement_integration_audit.py` checks IDs and integration wiring. +### Achievement spell payload (v39.16.60) +- `TarinaiAchievements.exportSpellState()` emits a compact array: unlock bitset, delta-coded timestamps, and packed persistent counters. +- `snapshot_system.js` includes it as `snapshot.g.s` only for exported spells and merges it through `importSpellState()` on load. +- `save_system.js` requests achievement inclusion for spell export; internal save slots do not include global achievement state. + +- `save_codec.js` schema 42 writes achievement metadata directly as sparse binary fields instead of a JSON string and can still decode schema 41 spell saves. +- v39.16.60: Added 狙撃手, メガロポリス, and 豊穣ヲ希求スル者; restricted 混沌ヲ希求スル者 to fight-mochi-influenced fights; extended compact achievement spell progress and omitted counters for already-unlocked achievements. diff --git a/BUILD_NOTE.txt b/BUILD_NOTE.txt index 47d5802..b87f01e 100644 --- a/BUILD_NOTE.txt +++ b/BUILD_NOTE.txt @@ -5,8 +5,8 @@ tarinai_compact_save_stage4 - The binary header contains one schema byte; its high bit signals whether a string table follows. Empty string tables and the duplicate snapshot version are omitted. - Deflate state is folded into the low bit of the frame-length varuint, eliminating the separate compression byte. - 15-bit text conversion uses arithmetic Unicode range mapping instead of a 32768-character string and reverse Map. -- Previous binary schemas are intentionally unsupported. -- Version: 39.16.56 +- Binary schema 41 is accepted for legacy v39.16.57 spells; new exports use schema 42. +- Version: 39.16.60 - CompressionStream and DecompressionStream are drained concurrently to avoid browser backpressure stalls. - Load confirmation uses the in-game dialog; fan wind is realtime; zunchi tool preview opacity, carried plushie depth, and blanket grass rules were corrected. @@ -85,3 +85,8 @@ tarinai_compact_save_stage4 39.16.55: Added 町のお医者さん and 割とふわふわ; changed ベビーブーム to 30 births per minute and 管理された楽園 to one uninterrupted happy in-game day from play day 6; repaired shared つつく targeting, damage, plushie fling, and hover overlay; corrected manual rotator/reciprocator push direction; tightened tool/limit typography; reduced periodic achievement scans; and changed server aggregate writes to compact v2 JSON with legacy-state migration. 39.16.56: Added 混沌ヲ希求スル者 and 潔癖症; made fight progress persistent; revised ミニマリスト, おくすり手帳全埋め, and 清掃業者; and made achievement-rate bars visible on unlocked cards. + +39.16.57: Compactly embeds unlocked achievements and persistent achievement progress in exported spell saves; spell loads merge achievements without erasing local progress and resync restored unlocks to the server. + +39.16.59: Replaced JSON-string achievement metadata in spell/save binaries with a sparse binary schema; achievement unlock masks are raw bits, progress is bit-packed, timestamps use minute deltas, and old v39.16.57 spells remain readable. +39.16.60: Added persistent sniper, megalopolis, and love-mochi fertility achievements; changed chaos progress to fight-mochi-influenced fights only; extended compact spell progress without migrating obsolete generic fight counts; omitted completed achievement counters from spell metadata; and tightened population-limit labels/layout. diff --git a/FILES.json b/FILES.json index d3b6de5..cf94b15 100644 --- a/FILES.json +++ b/FILES.json @@ -1,6 +1,6 @@ { "purpose": "Token-efficient machine-readable routing for tarinai_. Use scripts/ai_inventory.py for exact current file expansion.", - "version": "39.16.56", + "version": "39.16.60", "entrypoints": { "app": "index.html", "runtime": "js/main.js", diff --git a/GAME_FEATURES.md b/GAME_FEATURES.md index fb48893..559f968 100644 --- a/GAME_FEATURES.md +++ b/GAME_FEATURES.md @@ -73,9 +73,9 @@ Manual save and restore use browser storage. Reset returns to field selection an Display settings control effects, shadows, drawing detail, and quality choices for crowded scenes. Crowded fields are an intended part of the sandbox, so the game uses spatial lookup, scheduling, cached drawing, and incremental maintenance systems to keep large colonies and many objects playable. -## Achievement system (v39.16.56) -- Fifty-one achievements track reproduction, natural status changes, generation runs, rapid population events, special deaths, colony conditions, individual care, autonomous ecology, history usage, cleanup, rapid deletion, temperature transitions, weather shelter, medicine-category completion, combat reversals, and ant-related play styles. -- Locked rows reveal only the configured condition allowlist; all others show `???`. There are no achievement tooltips. 大いなる母, めっちゃたりない観察, and 敵の敵は味方 include local progress percentages, and unlocked achievements are sorted first inside each category. +## Achievement system (v39.16.60) +- Fifty-four achievements track reproduction, natural status changes, generation runs, rapid population events, special deaths, colony conditions, individual care, autonomous ecology, history usage, cleanup, rapid deletion, temperature transitions, weather shelter, medicine-category completion, combat reversals, and ant-related play styles. +- Locked rows reveal only the configured condition allowlist; all others show `???`. There are no achievement tooltips. 大いなる母, めっちゃたりない観察, 敵の敵は味方, 混沌ヲ希求スル者, and 豊穣ヲ希求スル者 include local progress percentages, and unlocked achievements are sorted first inside each category. - Each achievement row behaves as a horizontal bar chart. Its background fill visualizes the optional global completion percentage from 0–100%, and the global achiever count is displayed beside it. - `物でいっぱい` requires 100 cumulative player placements across field resets. `害虫駆除` requires 100 cumulative ant kills across field resets. - `餌やりじいさん` requires 33 direct feedings in one field; resetting the field resets this progress. @@ -84,3 +84,11 @@ Display settings control effects, shadows, drawing detail, and quality choices f - v39.16.54 added 真・たりない観察, 悠久の歴史, 五体満足, and 零体満足. v39.16.55 added 町のお医者さん for 50 effective first-aid recoveries and 割とふわふわ for flinging a plushie with つつく. ベビーブーム now requires 30 births in one minute; 管理された楽園 starts tracking from play day 6 and requires one uninterrupted happy in-game day. - Local unlocks and persistent totals live in browser storage. Field-scoped direct-feeding, cleaner, self-sufficiency, enemy-ant, generation, observation, safety, and per-entity/item progress follow current-format saves where applicable. Nest-box and pipe occupants block rain/weather effects and count as sheltered for 雨宿り完了. - Achievement evaluation is primarily event-driven; periodic world scans skip completed or irrelevant conditions. The server writes compact v2 achievement aggregate JSON while continuing to read the earlier verbose state format. + +### Achievement spell persistence (v39.16.60) +- Exported spells compactly include non-debug achievement unlocks, unlock times, and persistent progress. +- Loading a spell merges achievements and keeps the greater progress instead of erasing local achievement data. +- Restored unlocks are queued for the existing server recovery synchronization. Save slots remain world-only. + +- Spell achievement metadata uses a sparse binary encoding: raw unlock bits, bit-packed persistent progress, minute-delta unlock timestamps, and sparse per-entity state. Legacy JSON-metadata spells remain readable. +- v39.16.60: Added 狙撃手, メガロポリス, and 豊穣ヲ希求スル者; restricted 混沌ヲ希求スル者 to fight-mochi-influenced fights; extended compact achievement spell progress and omitted counters for already-unlocked achievements. diff --git a/README.md b/README.md index e440d79..607a6ae 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ AI-first entrypoint for a static browser simulation/game. Keep this file small; - v39.16.47 changes: Two achievements are added (大いなる母 and 喧嘩両成敗); five names and five revealed descriptions are revised; `?debug=1` exposes an all-achievements button. - v39.16.46 changes: achievement names and presentation are revised; conditions are revealed only after unlock; shared completion rates render as horizontal background bars; automation and link coverage merge into 機械化産業; placement and ant-kill targets are persistent totals of 100; direct feeding resets with the field. - v39.16.45 changes: seven play-style achievements add passive observation, cumulative placement, detector automation, link-tool coverage, safe large-colony operation, ant population, and ant elimination measurements. World-scoped timers and placement counts persist in current-format saves. -- No bundler; `index.html` loads ordered global-IIFE scripts with `?v=39.16.56`. +- No bundler; `index.html` loads ordered global-IIFE scripts with `?v=39.16.60`. - v39.16.31 changes: all in-world tooltips use the closer offset; Hair Trigger adds a central bounce-fence ball enclosure with Tarinai and pet-food duplicators outside; physics tools use distinct icons. - v39.16.29 changes: parasol placement preview now uses the exact shade center and footprint; toilet sand absorbs rain-created water drops. Happy adds parasols, water balloons, and toilet sand beneath each duplicator; Athletic uses fence-safe single-bar rotators and water balloons; War adds rotating fans. - v39.16.19 changes: food and medicine can be given directly by placement or pinched drop, with a dedicated overlay, food heart bursts, and stronger personality effects; unused collision reasons and duplicate constraint projection dirty checks were removed. @@ -72,11 +72,11 @@ Colony birth/death chart lines, reverse rotators, champion-trait inheritance, re - v39.16.39 changes: restored the compact sticky operation palette, added exact-match right-panel search, reorganized colony settings, and refreshed tool icons. -## Achievement system (v39.16.56) -- Fifty-one local achievements cover biological events, special deaths, colony conditions, individual care, passive ecology, Undo/Redo behavior, rapid deletion, cleaner use, temperature transitions, medicine-category completion, weather shelter, combat reversals, and ant-related play styles. +## Achievement system (v39.16.60) +- Fifty-four local achievements cover biological events, special deaths, colony conditions, individual care, passive ecology, Undo/Redo behavior, rapid deletion, cleaner use, temperature transitions, medicine-category completion, weather shelter, combat reversals, and ant-related play styles. - Locked entries show the configured pre-unlock disclosure directly in the row; all other locked entries show `???`. 大いなる母, めっちゃたりない観察, and 敵の敵は味方 show local progress percentages. Unlocked entries appear first within each category. - Each entry is a horizontal completion-rate bar whose background fill reflects the optional shared global unlock percentage; the shared achiever count appears beside the percentage. -- v39.16.54 added 真・たりない観察, 悠久の歴史, 五体満足, and 零体満足. v39.16.55 added 町のお医者さん for 50 effective first-aid recoveries and 割とふわふわ for flinging a plushie with つつく; both are event-driven and 町のお医者さん is disclosed before unlock. v39.16.56 adds two more achievements, persistent fight progress, stricter robot-only evaluation, revised thresholds, and unlocked-card rate bars. +- v39.16.54 added 真・たりない観察, 悠久の歴史, 五体満足, and 零体満足. v39.16.55 added 町のお医者さん for 50 effective first-aid recoveries and 割とふわふわ for flinging a plushie with つつく; both are event-driven and 町のお医者さん is disclosed before unlock. v39.16.56 added two achievements, persistent fight progress, stricter robot-only evaluation, revised thresholds, and unlocked-card rate bars. v39.16.60 adds three achievements and restricts the chaos counter to fight-mochi-influenced fights. - Persistent totals include 物でいっぱい, 害虫駆除, 大いなる母(3333体), 無計画都市, やっぱなし, and やっぱあり. Field-local progress includes 餌やりじいさん, 清掃業者, 自給自足, and 敵の敵は味方; applicable field-local metadata follows current-format saves. - `自動化の第一歩` and `リンク職人` are retired and replaced by `機械化産業`, which requires both detector-driven activation and rope/rod/spring coverage. Existing players with both retired achievements migrate automatically. - Optional same-origin PHP API aggregates anonymous player counts and global unlock percentages. Raw aggregate data is stored under `.achievement_data/state.json` in compact v2 arrays, with transparent reading/migration of the prior verbose format, and is protected by Apache rules. @@ -87,4 +87,6 @@ Colony birth/death chart lines, reverse rotators, champion-trait inheritance, re - PHP must be enabled, and `.achievement_data` must be writable by the PHP process. - On a static-only host, local unlocks still work; the global percentage is shown as unavailable. - Set `window.TARINAI_ACHIEVEMENT_API` before `achievements.js` to use a different same-origin endpoint. -- The current release tracks fifty-one achievement IDs, supports per-player reset, and accepts additive bulk synchronization for automatic recovery after aggregate-data loss. A separate backup remains necessary to recover players who never return. \ No newline at end of file +- The current release tracks fifty-one achievement IDs, supports per-player reset, and accepts additive bulk synchronization for automatic recovery after aggregate-data loss. A separate backup remains necessary to recover players who never return. +- v39.16.60 changes: achievement metadata in spells is now encoded as sparse binary data instead of embedded JSON; unlock masks, progress, timestamps, per-entity counters, and placement metadata are compactly packed while legacy v39.16.57 spell data remains readable. +- v39.16.60: Added 狙撃手, メガロポリス, and 豊穣ヲ希求スル者; restricted 混沌ヲ希求スル者 to fight-mochi-influenced fights; extended compact achievement spell progress and omitted counters for already-unlocked achievements. diff --git a/achievement_api.php b/achievement_api.php index 94c1d8f..d6dc995 100644 --- a/achievement_api.php +++ b/achievement_api.php @@ -57,6 +57,9 @@ const ACHIEVEMENT_IDS = [ 'chaos_seeker_666_fights', 'clean_freak_robot_only', 'true_tarinai_observer', + 'sniper_333_shots', + 'megalopolis', + 'fertility_seeker_721_love_births', ]; const DATA_DIR_NAME = '.achievement_data'; const DATA_FILE_NAME = 'state.json'; @@ -199,6 +202,7 @@ if (!valid_player_id($playerId)) { respond(['ok' => false, 'error' => 'invalid_player'], 400); } $syncUnlocks = []; +$completionistEligible = null; if ($action === 'unlock') { $achievementId = (string)($payload['achievementId'] ?? ''); if (!in_array($achievementId, ACHIEVEMENT_IDS, true)) { @@ -209,6 +213,12 @@ if ($action === 'unlock') { if (!is_array($submittedUnlocks) || count($submittedUnlocks) > count(ACHIEVEMENT_IDS)) { respond(['ok' => false, 'error' => 'invalid_unlocks'], 400); } + if (array_key_exists('completionistEligible', $payload)) { + if (!is_bool($payload['completionistEligible'])) { + respond(['ok' => false, 'error' => 'invalid_completionist_state'], 400); + } + $completionistEligible = $payload['completionistEligible']; + } foreach ($submittedUnlocks as $achievementId => $timestamp) { if (!is_string($achievementId) || !in_array($achievementId, ACHIEVEMENT_IDS, true)) { respond(['ok' => false, 'error' => 'invalid_achievement'], 400); @@ -256,6 +266,9 @@ try { $state['unlocks'][$achievementId][$playerId] = $now; } } elseif ($action === 'sync') { + if ($completionistEligible === false && isset($state['unlocks']['true_tarinai_observer'][$playerId])) { + unset($state['unlocks']['true_tarinai_observer'][$playerId]); + } foreach ($syncUnlocks as $achievementId => $submittedTimestamp) { if (!isset($state['unlocks'][$achievementId]) || !is_array($state['unlocks'][$achievementId])) { $state['unlocks'][$achievementId] = []; diff --git a/app_manifest.json b/app_manifest.json index 39a07a3..02cf606 100644 --- a/app_manifest.json +++ b/app_manifest.json @@ -1,5 +1,5 @@ { - "version": "39.16.56", + "version": "39.16.60", "css": [ "css/base.css", "css/layout.css", diff --git a/css/components.css b/css/components.css index f7c23e1..88b122b 100644 --- a/css/components.css +++ b/css/components.css @@ -1229,3 +1229,14 @@ /* v39.16.56: keep the upper-limit heading on one line in the compact panel. */ .colony-limit-section .colony-setting-section-head > span { font-size: 10.8px; white-space: nowrap; } .colony-limit-section .colony-setting-section-head > small { font-size: 9px; white-space: nowrap; } + +/* v39.16.60: align both upper-limit sliders independently of label length. */ +.colony-limit-grid { display: grid; gap: 7px; } +.colony-limit-row { display: grid; grid-template-columns: 82px minmax(0, 1fr) 58px; align-items: center; gap: 8px; min-width: 0; } +.colony-limit-row > span { min-width: 0; font-size: 11px; font-weight: 700; white-space: nowrap; } +.colony-limit-slider { width: 100%; min-width: 0; margin: 0; } +.colony-limit-number { width: 58px; min-width: 0; box-sizing: border-box; } +@media (max-width: 520px) { + .colony-limit-row { grid-template-columns: 72px minmax(0, 1fr) 54px; gap: 6px; } + .colony-limit-number { width: 54px; } +} diff --git a/index.html b/index.html index 4ef0673..2cab199 100644 --- a/index.html +++ b/index.html @@ -4,14 +4,14 @@