diff --git a/PATCH_NOTES.md b/PATCH_NOTES.md index a18517f..3bbdf03 100644 --- a/PATCH_NOTES.md +++ b/PATCH_NOTES.md @@ -121,3 +121,128 @@ - Removed the remaining synchronous family-tree DFS fallback blocks in `ui_family_data.js` and `ui_family_render.js`; both now use `TarinaiFamilyGraph.connectedComponents()`. - Simplified the remaining manual ant proximity fallback in `tarinai_needs_items.js` to `world.nearbyAnts()`. - Verification: all `js/*.js` and `service-worker.js` pass `node --check`. + +## 15.25.0 save/load UI and pin UI fix +- Fixed `Item.draw()` crash caused by an undefined `isOshibyo` local in the pin drawing branch. +- Reworked the save dialog into a 3x3 slot grid and added per-slot canvas thumbnails. +- Added compressed `TARINAI_SAVE_V2:` hash export/import using browser gzip streams when available; legacy `TARINAI_SAVE_V1:` imports remain supported. +- Replaced browser confirm prompts in save/load/import/delete flows with in-game save dialog confirmation UI. +- Added missing tool UI icons for `pushpin` and `oshibyo` and updated their tooltips. +- Renamed tool categories: 操作, 飲食, 薬, 生活, 危険物. Moved freeze to 操作 and fences to 生活. +- Made the frozen individual panel initially collapsed. +- Made colony mood span the full colony UI width with a compact height. +- Moved push notification cards inside the top of the Event UI. +- Bumped static cache version to `15.25.0`. + +## v15.26.0 save/sunbath/signboard/freeze UI patch +- ずんちどれいの食対象を、ずんだ餅・草・水系を除く食べ物全般へ拡張。 +- 看板を大型化し、観察/看板ツールでクリック編集、配置直後編集に対応。 +- 日光浴の開始処理が呼ばれていなかった問題を修正し、発生確率と継続時間を大幅に増加。 +- フィールド内の非地形オブジェクト・たりない・アリをY座標で統合ソートし、下側が前に出る描画順へ調整。 +- 冷凍ボタンを操作カテゴリから廃止し、冷凍個体一覧を操作カテゴリ内部へ移動。 +- セーブスロットを小型化し、サムネイルをスロット全面背景として表示。 +- ハッシュ書き出しをV3コンパクト形式へ変更。イベントログ、エフェクト、吹き出し等の非本体情報は保存対象外。 +- α版のため、セーブ/ハッシュ互換性は当面保証しない旨をコードコメントに明記。 + +## v15.27.0 hash V4 / layer / warning patch +- ハッシュ書き出しを `TARINAI_SAVE_V4:` に更新。V3の密な配列形式から、短い疎配列形式へ変更。 +- V4ではゲームプレイ本体に必要な world / tarinai / item / ant / frozen 状態のみを保存し、ログ、イベント表示、エフェクト、吹き出し、サムネイル等は保存対象外。 +- アイテム種別・スプライト種別は固定辞書の数値コードで保存し、初期状態で全アイテムを1つずつ置いたケースでも短くなるようにした。 +- アイテムは `type,x,y` をヘッダ化し、その他はデフォルト値から変化した値だけを保存する方式へ変更。 +- 干草寝床の描画レイヤーを同じY座標の他オブジェクトより少し後ろへ調整。 +- ロード/インポート/削除の上書き警告を中央の大きなゲーム内UIとして表示。 +- キャッシュ対策としてバージョンを `15.27.0` へ更新。 + +## v15.28.0 machine / pin placement patch +- おしり鋲を約半分の表示サイズに縮小し、刺さり位置をたりないスプライト右側へ移動。 +- 画鋲/おしり鋲の刺さり表示は、たりないのスプライト反転に合わせて左右反転するよう調整。 +- 新アイテム「複製機」を追加。消費アイテムツールで複製機をクリックするとスロットにセットし、下側の皿へ無限補充する。 +- 新アイテム「大砲」を追加。消費アイテムツールで大砲をクリックするとスロットにセットし、クリック位置で360度向きを変更し、セット品を撃ち出す。 +- 大砲弾として飛んだ消費アイテムは、高速時にたりないへ当たるとボール同様に吹き飛ばす。 +- 複製機/大砲の道具UIアイコンを追加。 +- セーブV4のアイテム種別表・追加キーへ複製機/大砲および機械スロット情報を追加。 +- キャッシュ対策としてバージョンを `15.28.0` へ更新。 + +## v15.29.0 asset / save compression patch +- 全たりないスプライトを 512x468 以下に収まるよう縮小し、WebP を再圧縮。 +- `ALPHA_BOUNDS` を現行画像寸法と透過領域から再生成。 +- 音声サンプルを軽量 MP3 に置き換え、WAV を配布対象から除外。 +- セーブハッシュ内の座標系数値は小数点第一位までに丸めるよう変更。 +- コメントは削除せず、JS minify は行っていない。 +- キャッシュ対策としてバージョンを `15.29.0` へ更新。 + +## v15.30.0 save hash v5 compact patch +- ハッシュ書き出しを `TARINAI_SAVE_V5:` に更新。 +- V5はトップレベルを短い配列形式にし、world / たりない / item / ant / 冷凍個体をゲームプレイに必要な値だけで再パック。 +- たりないの性格・遺伝・関係性・効果タイマー・状態/欲求/アイテム種別を短い配列または数値コード化。 +- 初期値・決定論的に再生成できる値・UI/演出専用値はハッシュ保存対象から除外。 +- 座標は引き続き小数点第一位まで保存。 +- V4/V3/V2/V1の読み込み互換は一応残すが、α版のため今後の互換性保証はしない。 +- キャッシュ対策としてバージョンを `15.30.0` へ更新。 + +## 15.31.0 - Hash V6 compaction + +- Added `TARINAI_SAVE_V6:` export format. +- Further shortened hash text while preserving gameplay state. +- Removed individual observation history/name fields from hash exports: + - names + - former names + - parent display names + - personality daily history + - mystery drug history + - recent change records + - per-individual observation records +- Replaced long family keys in hash payload with compact numeric family references. +- Encoded live IDs like `t12` as numeric IDs in hash payload and restored them on load. +- Packed tarinai core gameplay stats into fixed compact rows. +- Kept gameplay-critical data: + - needs/status + - position and movement-relevant values + - personality and genetics + - parent/child links + - relationships + - diseases + - zunchi slave state + - item effects + - oshibyo/zunchi stock + - sunbath/fear/fall gameplay timers + - items, machines, ants, frozen tarinai +- Flattened item base records remains active from V6 export. +- Hash remains ASCII base64url + gzip for copy/paste and editor durability. + +## 15.32.0 - Hash V7 base91/name preservation + +- Added `TARINAI_SAVE_V7:` hash export. +- V7 uses gzip plus a 91-character printable ASCII transport alphabet instead of base64url. +- V7 keeps individual names in compact hash exports. +- V7 excludes dead tarinai rows from compact hash exports so family graph history does not revive/save dead individuals. +- V7 filters parent/child and relationship links to living or frozen individuals; pending frozen death notices remain gameplay data. +- V7 stores selected numeric tarinai stats as relative deltas from common defaults while preserving the existing compact numeric precision. +- V1-V6 import support remains. + +## 15.33.0 - Hash V8 current-only compact save +- Hash exports now use `TARINAI_SAVE_V8:` only. Old hash import compatibility was intentionally removed for the alpha save format. +- Added an untouched-initial-colony sentinel. Initial colonies now export as a compact reset marker plus names instead of full entity/item rows, targeting roughly 100 characters for the initial state depending on generated names. +- Frozen individual save data no longer preserves pending death notices or relationship/memory records. +- Dead family nodes remain omitted from compact hash saves. +- Individual names are preserved in V8 compact saves. +- V8 keeps printable ASCII transport using the 91-character alphabet, with an explicit compressed/uncompressed mode marker. + + +## 15.34.0 - Hash V9 binary compact format + +- Removed the V8 initial-state-only save sentinel. All states now use the same compact format. +- Export hash format is now `TARINAI_SAVE_V9:` and legacy hash imports are rejected during alpha. +- Replaced JSON-based compact hashes with a dedicated binary packet plus printable ASCII Base94 transport. +- Stopped saving elapsed day count in compact hash; loaded compact hashes restore day as 1. +- Kept custom individual names, while default four-character names made only from `は / う / ぅ / っ` are packed as 2-bit character codes. +- Replaced saved tarinai/item IDs and family keys with array-index references; IDs are regenerated on load. +- Uses default-relative numeric deltas, optional timer tags, boolean bit fields, and 0.1-unit integer coordinates. +- Keeps gameplay-critical tarinai needs, personality, genetics, family links, relationships, item states, machines, ants, and frozen individuals; frozen pending-loss memory remains omitted. + +## 15.35.0 - Hash V10 compact packet +- Changed exported hash prefix to `TARINAI-SAVE-V10:` so the full hash text no longer uses `_` in its version marker. +- Excluded `\\`, `*`, `'`, and `_` from the printable ASCII transport alphabet. +- Replaced the V9 generic array/value packet with a V10 field-specific binary packet for common gameplay data. +- Kept gameplay-critical state while reducing overhead for names, world data, tarinai core rows, item rows, ants, and frozen individuals. +- Kept elapsed day count out of the hash; loads restore to day 1. diff --git a/app_manifest.json b/app_manifest.json index fdd5ec8..d46ce4a 100644 --- a/app_manifest.json +++ b/app_manifest.json @@ -1,5 +1,5 @@ { - "version": "15.24.0", + "version": "15.35.0", "css": [ "css/base.css", "css/layout.css", @@ -20,6 +20,7 @@ "js/food_registry.js", "js/input_mode_manager.js", "js/math.js", + "js/need_behavior_system.js", "js/physics_helpers.js", "js/assets.js", "js/audio.js", @@ -74,7 +75,6 @@ "assets/ui/*.webp", "assets/objects/*.webp", "assets/sprites/*.webp", - "assets/sounds/*.wav", "assets/sounds/*.mp3" ], "notes": "Source of truth for static loading order; generated files are index.html script/link tags and service-worker.js cache list." diff --git a/assets/sounds/firecracker_explosion.mp3 b/assets/sounds/firecracker_explosion.mp3 index 9e23327..4637d8c 100644 Binary files a/assets/sounds/firecracker_explosion.mp3 and b/assets/sounds/firecracker_explosion.mp3 differ diff --git a/assets/sounds/voice_001_hau.mp3 b/assets/sounds/voice_001_hau.mp3 new file mode 100644 index 0000000..0d09a25 Binary files /dev/null and b/assets/sounds/voice_001_hau.mp3 differ diff --git a/assets/sounds/voice_002_flee.mp3 b/assets/sounds/voice_002_flee.mp3 new file mode 100644 index 0000000..22d3e76 Binary files /dev/null and b/assets/sounds/voice_002_flee.mp3 differ diff --git a/assets/sounds/voice_003_po.mp3 b/assets/sounds/voice_003_po.mp3 new file mode 100644 index 0000000..fa22f4a Binary files /dev/null and b/assets/sounds/voice_003_po.mp3 differ diff --git a/assets/sounds/voice_004_eat.mp3 b/assets/sounds/voice_004_eat.mp3 new file mode 100644 index 0000000..5104258 Binary files /dev/null and b/assets/sounds/voice_004_eat.mp3 differ diff --git a/assets/sounds/voice_005_stress.mp3 b/assets/sounds/voice_005_stress.mp3 new file mode 100644 index 0000000..f11ed1c Binary files /dev/null and b/assets/sounds/voice_005_stress.mp3 differ diff --git a/assets/sounds/voice_006_sleep.mp3 b/assets/sounds/voice_006_sleep.mp3 new file mode 100644 index 0000000..a594c7c Binary files /dev/null and b/assets/sounds/voice_006_sleep.mp3 differ diff --git a/assets/sprites/tarinai_01_smile.webp b/assets/sprites/tarinai_01_smile.webp index bcaab40..34aa6f8 100644 Binary files a/assets/sprites/tarinai_01_smile.webp and b/assets/sprites/tarinai_01_smile.webp differ diff --git a/assets/sprites/tarinai_02_angry.webp b/assets/sprites/tarinai_02_angry.webp index 643c5ad..1ee98e4 100644 Binary files a/assets/sprites/tarinai_02_angry.webp and b/assets/sprites/tarinai_02_angry.webp differ diff --git a/assets/sprites/tarinai_03_teary.webp b/assets/sprites/tarinai_03_teary.webp index 85ecf3b..5b65d0e 100644 Binary files a/assets/sprites/tarinai_03_teary.webp and b/assets/sprites/tarinai_03_teary.webp differ diff --git a/assets/sprites/tarinai_04_jito.webp b/assets/sprites/tarinai_04_jito.webp index 068dd35..71ba6e6 100644 Binary files a/assets/sprites/tarinai_04_jito.webp and b/assets/sprites/tarinai_04_jito.webp differ diff --git a/assets/sprites/tarinai_05_drool.webp b/assets/sprites/tarinai_05_drool.webp index b0cca44..48fe575 100644 Binary files a/assets/sprites/tarinai_05_drool.webp and b/assets/sprites/tarinai_05_drool.webp differ diff --git a/assets/sprites/tarinai_06_cry.webp b/assets/sprites/tarinai_06_cry.webp index a823445..c99d104 100644 Binary files a/assets/sprites/tarinai_06_cry.webp and b/assets/sprites/tarinai_06_cry.webp differ diff --git a/assets/sprites/tarinai_07_sleep.webp b/assets/sprites/tarinai_07_sleep.webp index c378529..244a9b1 100644 Binary files a/assets/sprites/tarinai_07_sleep.webp and b/assets/sprites/tarinai_07_sleep.webp differ diff --git a/assets/sprites/tarinai_08_pokan.webp b/assets/sprites/tarinai_08_pokan.webp index e1e6b2a..32debce 100644 Binary files a/assets/sprites/tarinai_08_pokan.webp and b/assets/sprites/tarinai_08_pokan.webp differ diff --git a/assets/sprites/tarinai_09_stretch.webp b/assets/sprites/tarinai_09_stretch.webp index c8a245b..e1920ae 100644 Binary files a/assets/sprites/tarinai_09_stretch.webp and b/assets/sprites/tarinai_09_stretch.webp differ diff --git a/assets/sprites/tarinai_10_hurt.webp b/assets/sprites/tarinai_10_hurt.webp index e53c759..38aeeff 100644 Binary files a/assets/sprites/tarinai_10_hurt.webp and b/assets/sprites/tarinai_10_hurt.webp differ diff --git a/assets/sprites/tarinai_11_weak.webp b/assets/sprites/tarinai_11_weak.webp index 4a36e52..7e8e906 100644 Binary files a/assets/sprites/tarinai_11_weak.webp and b/assets/sprites/tarinai_11_weak.webp differ diff --git a/assets/sprites/tarinai_12_back.webp b/assets/sprites/tarinai_12_back.webp index 3a60bfb..59b4913 100644 Binary files a/assets/sprites/tarinai_12_back.webp and b/assets/sprites/tarinai_12_back.webp differ diff --git a/assets/sprites/tarinai_13_flee.webp b/assets/sprites/tarinai_13_flee.webp index 047449c..aee8512 100644 Binary files a/assets/sprites/tarinai_13_flee.webp and b/assets/sprites/tarinai_13_flee.webp differ diff --git a/assets/sprites/tarinai_14_zunda_eat.webp b/assets/sprites/tarinai_14_zunda_eat.webp index 06c956b..b42cb65 100644 Binary files a/assets/sprites/tarinai_14_zunda_eat.webp and b/assets/sprites/tarinai_14_zunda_eat.webp differ diff --git a/assets/sprites/tarinai_15_hurt2.webp b/assets/sprites/tarinai_15_hurt2.webp index a79cf25..261edb7 100644 Binary files a/assets/sprites/tarinai_15_hurt2.webp and b/assets/sprites/tarinai_15_hurt2.webp differ diff --git a/assets/sprites/tarinai_16_normal_smirk.webp b/assets/sprites/tarinai_16_normal_smirk.webp index 4029f70..1809751 100644 Binary files a/assets/sprites/tarinai_16_normal_smirk.webp and b/assets/sprites/tarinai_16_normal_smirk.webp differ diff --git a/assets/sprites/tarinai_17_normal_tongue.webp b/assets/sprites/tarinai_17_normal_tongue.webp index 8623cec..09acce1 100644 Binary files a/assets/sprites/tarinai_17_normal_tongue.webp and b/assets/sprites/tarinai_17_normal_tongue.webp differ diff --git a/assets/sprites/tarinai_18_fear.webp b/assets/sprites/tarinai_18_fear.webp index 245190b..81e0b15 100644 Binary files a/assets/sprites/tarinai_18_fear.webp and b/assets/sprites/tarinai_18_fear.webp differ diff --git a/assets/sprites/tarinai_19_flee_fear2.webp b/assets/sprites/tarinai_19_flee_fear2.webp index f10ac23..cd9185d 100644 Binary files a/assets/sprites/tarinai_19_flee_fear2.webp and b/assets/sprites/tarinai_19_flee_fear2.webp differ diff --git a/assets/sprites/tarinai_20_sleep2.webp b/assets/sprites/tarinai_20_sleep2.webp index 63b558f..c5da8b3 100644 Binary files a/assets/sprites/tarinai_20_sleep2.webp and b/assets/sprites/tarinai_20_sleep2.webp differ diff --git a/assets/sprites/tarinai_21_normal_happy.webp b/assets/sprites/tarinai_21_normal_happy.webp index 2d1df1f..b7a724c 100644 Binary files a/assets/sprites/tarinai_21_normal_happy.webp and b/assets/sprites/tarinai_21_normal_happy.webp differ diff --git a/assets/sprites/tarinai_22_fear_blue.webp b/assets/sprites/tarinai_22_fear_blue.webp index 99eb408..7c35c7d 100644 Binary files a/assets/sprites/tarinai_22_fear_blue.webp and b/assets/sprites/tarinai_22_fear_blue.webp differ diff --git a/assets/sprites/tarinai_23_fear_cry.webp b/assets/sprites/tarinai_23_fear_cry.webp index cd7687a..f59bdab 100644 Binary files a/assets/sprites/tarinai_23_fear_cry.webp and b/assets/sprites/tarinai_23_fear_cry.webp differ diff --git a/assets/sprites/tarinai_24_stress_dizzy.webp b/assets/sprites/tarinai_24_stress_dizzy.webp index b0367ed..65a477e 100644 Binary files a/assets/sprites/tarinai_24_stress_dizzy.webp and b/assets/sprites/tarinai_24_stress_dizzy.webp differ diff --git a/assets/sprites/tarinai_25_stress_sweat.webp b/assets/sprites/tarinai_25_stress_sweat.webp index 1a537e1..763d8c2 100644 Binary files a/assets/sprites/tarinai_25_stress_sweat.webp and b/assets/sprites/tarinai_25_stress_sweat.webp differ diff --git a/assets/sprites/tarinai_26_intimidate.webp b/assets/sprites/tarinai_26_intimidate.webp index 4575fb1..efa6be7 100644 Binary files a/assets/sprites/tarinai_26_intimidate.webp and b/assets/sprites/tarinai_26_intimidate.webp differ diff --git a/assets/sprites/tarinai_27_birth_ritual.webp b/assets/sprites/tarinai_27_birth_ritual.webp index 1a75b86..d166672 100644 Binary files a/assets/sprites/tarinai_27_birth_ritual.webp and b/assets/sprites/tarinai_27_birth_ritual.webp differ diff --git a/assets/sprites/tarinai_28_zunchi_slave.webp b/assets/sprites/tarinai_28_zunchi_slave.webp index 8a4c59a..2fcf377 100644 Binary files a/assets/sprites/tarinai_28_zunchi_slave.webp and b/assets/sprites/tarinai_28_zunchi_slave.webp differ diff --git a/assets/sprites/tarinai_29_hungry_70.webp b/assets/sprites/tarinai_29_hungry_70.webp index becfb9f..85d93d9 100644 Binary files a/assets/sprites/tarinai_29_hungry_70.webp and b/assets/sprites/tarinai_29_hungry_70.webp differ diff --git a/assets/sprites/tarinai_30_zunchi_slave_alt.webp b/assets/sprites/tarinai_30_zunchi_slave_alt.webp index 07aac89..1f98640 100644 Binary files a/assets/sprites/tarinai_30_zunchi_slave_alt.webp and b/assets/sprites/tarinai_30_zunchi_slave_alt.webp differ diff --git a/assets/sprites/tarinai_31_sunbath_01.webp b/assets/sprites/tarinai_31_sunbath_01.webp index ea641b1..cbd7267 100644 Binary files a/assets/sprites/tarinai_31_sunbath_01.webp and b/assets/sprites/tarinai_31_sunbath_01.webp differ diff --git a/assets/sprites/tarinai_32_sunbath_02.webp b/assets/sprites/tarinai_32_sunbath_02.webp index edbbaa9..013dc52 100644 Binary files a/assets/sprites/tarinai_32_sunbath_02.webp and b/assets/sprites/tarinai_32_sunbath_02.webp differ diff --git a/assets/sprites/tarinai_33_sunbath_03.webp b/assets/sprites/tarinai_33_sunbath_03.webp index fb95759..316ceda 100644 Binary files a/assets/sprites/tarinai_33_sunbath_03.webp and b/assets/sprites/tarinai_33_sunbath_03.webp differ diff --git a/assets/ui/tool_cannon.webp b/assets/ui/tool_cannon.webp new file mode 100644 index 0000000..aa6db08 Binary files /dev/null and b/assets/ui/tool_cannon.webp differ diff --git a/assets/ui/tool_duplicator.webp b/assets/ui/tool_duplicator.webp new file mode 100644 index 0000000..8532570 Binary files /dev/null and b/assets/ui/tool_duplicator.webp differ diff --git a/assets/ui/tool_oshibyo.webp b/assets/ui/tool_oshibyo.webp new file mode 100644 index 0000000..8e2984d Binary files /dev/null and b/assets/ui/tool_oshibyo.webp differ diff --git a/css/base.css b/css/base.css index cb7924c..cf9df20 100644 --- a/css/base.css +++ b/css/base.css @@ -400,15 +400,15 @@ h1 { .tool[data-tool="water_bowl"] { --tool-icon: url("../assets/ui/tool_water_bowl.webp"); } /* Generated parameter item tool icons. */ -.tool[data-tool="laxative"] { --tool-icon: url("../assets/ui/tool_laxative.webp?v=15.20.16"); } -.tool[data-tool="protein"] { --tool-icon: url("../assets/ui/tool_protein.webp?v=15.20.16"); } -.tool[data-tool="niteropu"] { --tool-icon: url("../assets/ui/tool_niteropu.webp?v=15.20.16"); } -.tool[data-tool="ammo"] { --tool-icon: url("../assets/ui/tool_ammo.webp?v=15.20.16"); } -.tool[data-tool="mystery_drug"] { --tool-icon: url("../assets/ui/tool_mystery_drug.webp?v=15.20.16"); } -.tool[data-tool="mercury"] { --tool-icon: url("../assets/ui/tool_mercury.webp?v=15.20.16"); } -.tool[data-tool="giant_drug"] { --tool-icon: url("../assets/ui/tool_giant_drug.webp?v=15.20.16"); } -.tool[data-tool="dwarf_drug"] { --tool-icon: url("../assets/ui/tool_dwarf_drug.webp?v=15.20.16"); } -.tool[data-tool="zunda_juice"] { --tool-icon: url("../assets/ui/tool_zunda_juice.webp?v=15.20.16"); } +.tool[data-tool="laxative"] { --tool-icon: url("../assets/ui/tool_laxative.webp?v=15.33.0"); } +.tool[data-tool="protein"] { --tool-icon: url("../assets/ui/tool_protein.webp?v=15.33.0"); } +.tool[data-tool="niteropu"] { --tool-icon: url("../assets/ui/tool_niteropu.webp?v=15.33.0"); } +.tool[data-tool="ammo"] { --tool-icon: url("../assets/ui/tool_ammo.webp?v=15.33.0"); } +.tool[data-tool="mystery_drug"] { --tool-icon: url("../assets/ui/tool_mystery_drug.webp?v=15.33.0"); } +.tool[data-tool="mercury"] { --tool-icon: url("../assets/ui/tool_mercury.webp?v=15.33.0"); } +.tool[data-tool="giant_drug"] { --tool-icon: url("../assets/ui/tool_giant_drug.webp?v=15.33.0"); } +.tool[data-tool="dwarf_drug"] { --tool-icon: url("../assets/ui/tool_dwarf_drug.webp?v=15.33.0"); } +.tool[data-tool="zunda_juice"] { --tool-icon: url("../assets/ui/tool_zunda_juice.webp?v=15.33.0"); } .tool[data-tool="freeze"] { --tool-icon: none; } .tool[data-tool="freeze"]::before { content: "🧊"; @@ -418,3 +418,11 @@ h1 { text-align: center; } .tool[data-tool="freeze"]::after { content: "🧊"; background: none; font-size: 52px; right: -10px; left: auto; opacity: 0.08; display:flex; align-items:center; justify-content:flex-end; } + +/* v15.28.0: missing pin tool icons. */ +.tool[data-tool="pushpin"] { --tool-icon: url("../assets/ui/tool_pushpin.webp?v=15.33.0"); } +.tool[data-tool="oshibyo"] { --tool-icon: url("../assets/ui/tool_oshibyo.webp?v=15.33.0"); } + +/* v15.28.0: machine tool icons. */ +.tool[data-tool="duplicator"] { --tool-icon: url("../assets/ui/tool_duplicator.webp?v=15.33.0"); } +.tool[data-tool="cannon"] { --tool-icon: url("../assets/ui/tool_cannon.webp?v=15.33.0"); } diff --git a/css/components.css b/css/components.css index 1e02c43..0423b9e 100644 --- a/css/components.css +++ b/css/components.css @@ -454,6 +454,14 @@ .selected-info .info-row[data-metric="zunchi"] { background: rgba(112, 142, 70, 0.10); } .selected-info .info-row[data-metric="mood"] { background: rgba(222, 196, 86, 0.10); } .selected-info .info-row[data-metric="lack"] { background: rgba(142, 112, 184, 0.10); } +.selected-info .selected-need-row.active { + background: rgba(124, 198, 70, 0.18); + box-shadow: inset 3px 0 0 rgba(99, 166, 52, 0.78); +} +.selected-info .selected-need-mark { + color: rgba(72, 126, 42, 0.95); + font-size: 0.82em; +} .selected-personality-changes { align-items: start; } @@ -621,3 +629,179 @@ justify-content: flex-start; } } + +/* v15.25.0: save menu grid, thumbnails, compact import/export confirmation. */ +.save-dialog-panel { + width: min(860px, calc(100vw - 32px)); + max-height: min(88vh, 790px); +} +.save-slot-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; + margin: 14px 0; +} +.save-slot-card { + display: grid; + grid-template-rows: auto auto 1fr auto; + gap: 6px; + min-height: 190px; + padding: 9px; + border: 1px solid rgba(115, 91, 62, 0.20); + border-radius: 14px; + background: rgba(255, 255, 255, 0.58); + box-shadow: 0 2px 8px rgba(68, 52, 33, 0.06); +} +.save-slot-card.empty { + background: rgba(250, 247, 240, 0.54); +} +.save-slot-thumb { + height: 82px; + border-radius: 10px; + overflow: hidden; + background: linear-gradient(180deg, rgba(231, 221, 204, 0.80), rgba(245, 240, 230, 0.90)); + border: 1px solid rgba(115, 91, 62, 0.14); + display: grid; + place-items: center; +} +.save-slot-thumb img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.save-slot-thumb-empty { + font-size: 11px; + letter-spacing: .04em; + color: rgba(88, 72, 54, 0.48); + font-weight: 800; +} +.save-slot-title { + font-weight: 800; + color: #4f3928; + line-height: 1.15; +} +.save-slot-meta { + color: #6d5a46; + font-size: 12px; + line-height: 1.35; + min-height: 48px; +} +.save-slot-actions { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 5px; + justify-content: stretch; +} +.save-slot-actions .btn.mini { + min-width: 0; + padding-inline: 5px; +} +.save-confirm-box { + margin-top: 10px; + padding: 10px; + border-radius: 14px; + border: 1px solid rgba(169, 90, 73, 0.26); + background: rgba(255, 245, 236, 0.96); + box-shadow: inset 0 0 0 1px rgba(255,255,255,.62); +} +.save-confirm-box.hidden { display: none; } +.save-confirm-message { font-size: 13px; line-height: 1.45; color: #4f3928; } +.save-confirm-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:8px; } +.save-hash-text { min-height: 82px; } +@media (max-width: 740px) { + .save-slot-grid { grid-template-columns: 1fr; } + .save-slot-card { min-height: 0; } + .save-slot-thumb { height: 96px; } +} + +/* v15.25.0: compact full-width colony mood. */ +.colony-stats .stat:nth-child(3) { + grid-column: 1 / -1; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 5px 9px; + min-height: 28px; + text-align: left; +} +.colony-stats .stat:nth-child(3) span { font-size: 10px; } +.colony-stats .stat:nth-child(3) strong { font-size: 14px; line-height: 1.15; text-align: right; } + +/* v15.25.0: event push cards are contained at the top of the event UI. */ +.log-push-overlay { + position: static; + z-index: auto; + width: 100%; + margin: 0 0 8px; + display: flex; + flex-direction: column; + gap: 6px; + pointer-events: none; +} +.log-push-toast { + box-shadow: 0 6px 18px rgba(46, 34, 24, 0.13); + padding: 8px 10px 8px 13px; +} + +/* v15.28.0: smaller save slots with full-card thumbnails. */ +.save-dialog-panel { width: min(760px, calc(100vw - 32px)); max-height: min(88vh, 760px); } +.save-slot-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; } +.save-slot-card { position: relative; overflow: hidden; min-height: 126px; padding: 7px; grid-template-rows: auto 1fr auto; gap: 4px; background: rgba(255,255,255,.64); } +.save-slot-thumb { position: absolute; inset: 0; height: auto; border: 0; border-radius: inherit; z-index: 0; opacity: .88; } +.save-slot-thumb::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(255,250,241,.42), rgba(255,250,241,.78)); } +.save-slot-thumb img { object-fit: cover; } +.save-slot-thumb-empty { width:100%; height:100%; display:grid; place-items:center; background:rgba(240,234,222,.80); } +.save-slot-title, .save-slot-meta, .save-slot-actions { position: relative; z-index: 1; } +.save-slot-title { padding: 3px 6px; border-radius: 999px; background: rgba(255,251,244,.76); width: fit-content; } +.save-slot-meta { min-height: 34px; font-size: 11px; line-height: 1.25; padding: 5px 6px; border-radius: 10px; background: rgba(255,251,244,.70); } +.save-slot-actions { gap: 4px; } +.save-slot-actions .btn.mini { padding: 5px 4px; font-size: 11px; } +@media (max-width: 740px) { .save-slot-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } .save-slot-card { min-height: 118px; } } +@media (max-width: 520px) { .save-slot-grid { grid-template-columns: 1fr; } .save-slot-card { min-height: 128px; } } + +/* v15.28.0: frozen list lives inside the Operation tool category. */ +.tool-category[data-tool-category="operate"] .frozen-panel { grid-column: 1 / -1; margin: 4px 0 0; } + + +/* v15.28.0: large centered load/overwrite warning. */ +.save-confirm-box { + position: fixed; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 12000; + width: min(560px, calc(100vw - 32px)); + margin: 0; + padding: 22px 24px; + border-radius: 22px; + border: 2px solid rgba(169, 90, 73, 0.34); + background: rgba(255, 248, 239, 0.98); + box-shadow: 0 24px 70px rgba(42, 30, 18, 0.30), inset 0 0 0 1px rgba(255,255,255,.74); +} +.save-confirm-box::before { + content: ""; + position: fixed; + left: -100vw; + right: -100vw; + top: -100vh; + bottom: -100vh; + background: rgba(30, 22, 14, 0.24); + z-index: -1; +} +.save-confirm-message { + font-size: 18px; + line-height: 1.55; + font-weight: 800; + color: #4a2f23; +} +.save-confirm-actions { + margin-top: 18px; + gap: 12px; +} +.save-confirm-actions .btn { + min-width: 118px; + padding: 10px 16px; + font-size: 15px; +} diff --git a/css/mobile.css b/css/mobile.css index 9fedacb..60ec5ba 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -180,15 +180,15 @@ } /* Item icons and mobile input mode */ -.tool[data-tool="laxative"] { --tool-icon: url("../assets/ui/tool_laxative.webp?v=15.20.16"); } -.tool[data-tool="protein"] { --tool-icon: url("../assets/ui/tool_protein.webp?v=15.20.16"); } -.tool[data-tool="niteropu"] { --tool-icon: url("../assets/ui/tool_niteropu.webp?v=15.20.16"); } -.tool[data-tool="ammo"] { --tool-icon: url("../assets/ui/tool_ammo.webp?v=15.20.16"); } -.tool[data-tool="mystery_drug"] { --tool-icon: url("../assets/ui/tool_mystery_drug.webp?v=15.20.16"); } -.tool[data-tool="mercury"] { --tool-icon: url("../assets/ui/tool_mercury.webp?v=15.20.16"); } -.tool[data-tool="giant_drug"] { --tool-icon: url("../assets/ui/tool_giant_drug.webp?v=15.20.16"); } -.tool[data-tool="dwarf_drug"] { --tool-icon: url("../assets/ui/tool_dwarf_drug.webp?v=15.20.16"); } -.tool[data-tool="zunda_juice"] { --tool-icon: url("../assets/ui/tool_zunda_juice.webp?v=15.20.16"); } +.tool[data-tool="laxative"] { --tool-icon: url("../assets/ui/tool_laxative.webp?v=15.30.0"); } +.tool[data-tool="protein"] { --tool-icon: url("../assets/ui/tool_protein.webp?v=15.30.0"); } +.tool[data-tool="niteropu"] { --tool-icon: url("../assets/ui/tool_niteropu.webp?v=15.30.0"); } +.tool[data-tool="ammo"] { --tool-icon: url("../assets/ui/tool_ammo.webp?v=15.30.0"); } +.tool[data-tool="mystery_drug"] { --tool-icon: url("../assets/ui/tool_mystery_drug.webp?v=15.30.0"); } +.tool[data-tool="mercury"] { --tool-icon: url("../assets/ui/tool_mercury.webp?v=15.30.0"); } +.tool[data-tool="giant_drug"] { --tool-icon: url("../assets/ui/tool_giant_drug.webp?v=15.30.0"); } +.tool[data-tool="dwarf_drug"] { --tool-icon: url("../assets/ui/tool_dwarf_drug.webp?v=15.30.0"); } +.tool[data-tool="zunda_juice"] { --tool-icon: url("../assets/ui/tool_zunda_juice.webp?v=15.30.0"); } .mobile-mode-controls { display: none; position: absolute; @@ -239,3 +239,21 @@ body.touch-mobile-ui.mobile-mode-family .lineage-main-card { z-index: 9; } text-align: center; } .tool[data-tool="freeze"]::after { content: "🧊"; background: none; font-size: 52px; right: -10px; left: auto; opacity: 0.08; display:flex; align-items:center; justify-content:flex-end; } + +/* v15.28.0: keep push notifications inside the event card on mobile too. */ +.log-push-overlay { + position: static; + z-index: auto; + width: 100%; + margin: 0 0 8px; + display: flex; + flex-direction: column; + gap: 6px; + pointer-events: none; +} +.tool[data-tool="pushpin"] { --tool-icon: url("../assets/ui/tool_pushpin.webp?v=15.30.0"); } +.tool[data-tool="oshibyo"] { --tool-icon: url("../assets/ui/tool_oshibyo.webp?v=15.30.0"); } + +/* v15.28.0: machine tool icons. */ +.tool[data-tool="duplicator"] { --tool-icon: url("../assets/ui/tool_duplicator.webp?v=15.30.0"); } +.tool[data-tool="cannon"] { --tool-icon: url("../assets/ui/tool_cannon.webp?v=15.30.0"); } diff --git a/docs/prompt.txt b/docs/prompt.txt index 636a065..1950df9 100644 --- a/docs/prompt.txt +++ b/docs/prompt.txt @@ -1,466 +1,860 @@ -You are working on the browser game "たりないコロニー" based on the current ZIP/project state, assumed to be v15.20.3. - -Goal: resolve the remaining internal design confusion and underdeveloped systems, while preserving existing gameplay unless explicitly requested below. - -Hard exclusions: - -* Do NOT implement field-size balance tuning. Specifically do not implement the previously proposed "field-specific balance correction" work. -* Do NOT implement save/load. -* Do NOT implement debug scenario modes. -* Do NOT redesign or expand the zunchi system. Keep zunchi mechanics and general design as-is, except where existing code must be connected through registries/events without changing behavior. -* Do NOT modify `docs/prompt.txt` if present. -* Do not introduce a build toolchain requirement. Plain static HTML/CSS/JS must still run directly. - -Primary requirements: - -1. Make item visuals single-source-of-truth. - -* Current problem: field item rendering, tool UI icons, generated WebP icons, documentation, and item definitions can diverge. -* Establish one canonical visual definition per item/tool. -* Field rendering must be the primary visual source, or both field rendering and UI preview must derive from the same canonical visual descriptor. -* The tool UI must never have an independently invented appearance. -* Create or consolidate a visual registry, for example `js/item_visual_registry.js`, with descriptors such as: - - * `renderer` - * `shape` - * `palette` - * `scale` - * `uiPreviewScale` - * `fieldScale` - * `accessibleShapeTraits` - * optional `emojiFallback` -* Update field rendering and UI icon generation/preview so they share this registry. -* Fix visual drift for all known drift-prone items: - - * ammo - * mystery drug - * laxative - * sleeping drug - * protein - * nietorop - * giant drug - * dwarf drug - * zunda juice - * mercury - * rain-water item - * ball -* Keep the rule in docs: UI icon is a preview of the field visual, not a separate design. -* Ensure scalable items correctly respond to small/medium/large placement size. - -2. Data-drive tool categories. - -* Current problem: tool category membership/order/color is partly hardcoded in HTML/CSS and not owned by tool data. -* Move tool categories into a data registry, for example `js/tool_registry.js` or `js/data.js`. -* The registry must define: - - * category id - * Japanese label - * color/theme class - * sort order - * tool ids included in that category -* Generate/build the tool UI from this registry at runtime. -* Keep collapsible category behavior. -* Keep simple category color coding. -* Remove duplicated static category definitions from `index.html` where possible. -* Category changes must require editing only the registry, not HTML. - -3. Convert EffectRegistry from display-only to real behavior ownership. - -* Current problem: `effect_registry.js` mainly handles labels/display/random candidates, while actual behavior remains scattered in Tarinai/item code. -* Promote `EffectRegistry` into the canonical owner for item effect metadata and behavior. -* Each effect should define, where relevant: - - * `id` - * Japanese label - * duration or permanent flag - * exclusive group - * stack behavior - * display color - * display summary - * modifiers - * `onApply(tarinai, context)` - * `onTick(tarinai, dt, context)` - * `onRemove(tarinai, context)` - * visual effect id - * bubble policy - * whether it is eligible for "怪しい薬" - * whether it is removed by "ずんだ汁" -* Migrate these item effects into the registry: - - * laxative - * protein - * nietorop - * ammo - * mystery drug - * mercury - * giant drug - * dwarf drug - * zunda juice clearing behavior - * heko mochi timed effect - * fight mochi timed effect - * sleeping drug if it changes behavior -* Existing semantics must remain: - - * laxative: emits zunchi every 3 seconds during effect; eating does not reduce hunger because it immediately passes through. - * protein: permanent; damage dealt x1.75; disease chance x0.5; red upward particles; mutually exclusive with nietorop; latest wins. - * nietorop: permanent; damage dealt x0.5; disease chance x2; purple downward particles; mutually exclusive with protein; latest wins. - * ammo: timed; walking speed x10; while moving, collision with Tarinai/ants knocks them away. - * mystery drug: grants random two effects from behavior-changing item effects and diseases. - * mercury: each consumption multiplicatively increases lifespan by x1.3. - * giant drug: permanent; size x3; damage x2; speed x1.5; 1 damage/sec; mutually exclusive with dwarf drug; latest wins. - * dwarf drug: permanent; size x0.25; damage x0.25; speed x0.5; 1 damage/sec; mutually exclusive with giant drug; latest wins. - * zunda juice: removes all removable item effects. -* "たりないデータ" must read active item effects from the registry, not hand-built scattered conditions. - -4. Add DiseaseRegistry and connect disease behavior. - -* Current problem: diseases are individual booleans/branches and are not uniformly represented. -* Add `DiseaseRegistry` or equivalent. -* It must define: - - * disease id - * Japanese label - * symptoms/behavior flags - * infection chance modifiers - * cure rules - * display text - * visual/bubble policy - * eligibility for mystery drug -* Migrate these diseases into registry metadata while preserving behavior: - - * zunchi disease - * sleep disease - * explosion disease - * fight disease -* Explosion disease infection probability must remain 15% where currently defined, with protein/nietorop disease multipliers applied to that base. -* Mystery drug must sample diseases through this registry. -* Zunda juice should remove item effects, not necessarily diseases, unless current semantics already remove a given disease; do not silently change disease cure rules. - -5. Add FoodRegistry and centralize food semantics. - -* Current problem: food interest, nutrition, decay, hygiene penalty, cures, and special exceptions are scattered. -* Add `FoodRegistry`. -* It must define: - - * item id/type - * Japanese label - * nutrition - * palatability/interest class - * decay profile - * hygiene penalty on decay - * special effect id, if eating applies an effect - * whether it counts as grass-like interest, zunda-mochi high interest, medicine-like low interest, water, corpse, etc. -* Preserve existing behavior: - - * zunda mochi remains highly attractive. - * most non-zunda foods remain only slightly more interesting than grass. - * all food naturally decays about twice per half-day, not continuously. - * decay slightly reduces hygiene stats at those discrete decay ticks. - * laxative effect prevents hunger reduction from eating. -* `Tarinai` food-seeking logic must consult `FoodRegistry`. -* Food decay logic must consult `FoodRegistry`. -* Tooltips/descriptions should remain Japanese and current user-facing wording must not regress. - -6. Separate WeatherSystem from water items. - -* Current problem: rain visual effects and rain-spawned items/water-like items are conceptually mixed. -* Create or isolate a `WeatherSystem`. -* Explicitly separate: - - * `rain_visual`: diagonal blue-ish streaks/lines falling at an angle. - * `rain_water_item`: horizontal oval water item dropped by rain. - * `water_bowl`: placed water object. - * `zunda_juice`: green horizontal oval liquid item. - * `mercury`: gray horizontal oval liquid item. -* Do not reuse rain visual renderer for item droplets. -* Do not render rain effect as oval droplets. Rain effect must be angled falling lines. -* Do not render zunda juice or mercury with diagonal lines. -* Preserve current rain gameplay behavior. -* Add code comments documenting the distinction so future changes do not confuse them. - -7. Apply event bus more broadly. - -* Current problem: logs, sounds, notifications, stats, effects, and debug traces are still partly direct calls. -* Use the existing event bus or strengthen it. -* Add domain events for: - - * `tool:placed` - * `item:eaten` - * `item:decayed` - * `effect:applied` - * `effect:removed` - * `disease:infected` - * `disease:cured` - * `tarinai:damaged` - * `tarinai:died` - * `tarinai:born` - * `fight:hit` - * `fight:lost` - * `fight:ended` - * `ant:spawned` - * `ant:grabbed` - * `ant:carried` - * `ant:died` - * `weather:changed` - * `rain:itemDropped` -* Logs, push notifications, audio, stats, and debug history should subscribe to events where practical. -* Do not rewrite everything destructively. Add event emission at central points first, then migrate obvious direct calls. -* Avoid duplicate logs/sounds. - -8. Sound system source-of-truth cleanup. - -* Current problem: `sound_pack.js` and `audio.js` both contain overlapping settings. -* Make `sound_pack.js` the canonical metadata source for: - - * sound id - * category - * volume multiplier - * cooldown - * sample path - * fallback synthesis profile -* `audio.js` should be the playback engine only: - - * loading samples - * fallback synthesis - * category enable/disable - * master gain - * cooldown enforcement - * concurrent voice limiting -* Keep the current user settings: - - * master effect sound on/off - * Tarinai voice - * notification - * operation -* Do not regress volume. The previous issue was that only the first sound was loud and subsequent sounds became too quiet. Preserve the fixed master gain behavior. -* Keep `?debug=1` showing recent sound IDs and sound-pack version. - -9. Mobile input manager. - -* Current problem: mobile operation UI has appeared on PC repeatedly. -* Add a single `InputModeManager` or equivalent. -* It must own: - - * `isTouchDevice` - * `isCompactViewport` - * `hasHover` - * `pointerCoarse` - * `userAgentMobile` - * `currentMode` - * `gestureState` - * whether canvas can pan - * whether canvas can place tools - * whether family tree is allowed to capture touch -* Mobile operation UI must appear only when the device is clearly touch-first: - - * coarse pointer - * no hover - * real touch support - * and either compact viewport or mobile/tablet UA -* Desktop PCs with touch screens must not automatically show the mobile UI unless the viewport/UA also indicates mobile/tablet. -* Add debug display of the input classification under `?debug=1`. -* Keep existing modes: - - * auto - * camera - * tool - * family tree - -10. Ant system cleanup and extension hooks, without broad balance changes. - -* Do not create a full new ant ecology balance pass. -* Do consolidate ant domain events and state names. -* Preserve existing behavior: - - * ants can carry sleeping Tarinai. - * sleeping Tarinai do not wake just because ants carry them. - * sleeping Tarinai do not counterattack ants while asleep. - * ants without nests either join another available nest or wander. - * empty nests are removed. - * queen ants are visually larger. -* Add clear extension hooks or comments for future ant ecology: - - * nest hunger - * nest growth - * queen reproduction - * worker lifecycle - * carrying success rate - * territorial behavior -* Do not implement those future mechanics now unless already present. - -11. Family tree: add personality tags. - -* The family tree currently records lineage but should expose personality more directly. -* Add compact personality tags to each Tarinai node/card in the family tree. -* Use existing personality axes: - - * aggression - * openness - * sociability - * neuroticism -* Tags should be short Japanese labels, for example: - - * aggressive/high aggression - * calm/low aggression - * curious/high openness - * cautious/low openness - * social/high sociability - * solitary/low sociability - * nervous/high neuroticism - * stable/low neuroticism -* Use at most 2-3 tags per node to avoid clutter. -* Make tags visually subtle and compact. -* Do not break existing family tree panning/zooming/layout. -* If a Tarinai is dead, still show its personality tags if data exists. - -12. Tarinai data panel: show recent change causes. - -* The Tarinai individual data panel must include recent reasons for personality/state changes. -* Add a small "recent change causes" section. -* Record recent causes when personality or important state changes happen, for example: - - * genkotsu damage: fear increase and openness decrease - * fight win/loss - * being carried by ants - * disease infection/cure - * protein/nietorop - * giant/dwarf drug - * mercury consumption - * zunda juice clearing effects - * sleep/wake transitions where meaningful - * stress/fear significant changes -* Store only a short rolling history per Tarinai, for example last 5-8 entries. -* Each entry should include: - - * Japanese short reason - * affected stat/effect - * approximate in-game time or "recent" -* This is UI/diagnostic information, not save/load. -* Do not add full persistence. - -13. Personality system visibility. - -* The existing personality axes are meaningful but currently not visible enough. -* In addition to family tree tags and recent change causes, improve the Tarinai data panel to make personality effects understandable: - - * show current personality values already present, if available - * show the most recent cause next to changed values where practical - * avoid long prose; use compact labels. -* Do not add new personality axes. - -14. Documentation consolidation and English-only high-density docs. - -* Keep `docs/prompt.txt` untouched. -* Keep documentation concise, English-only, and high information density. -* Update or consolidate docs so the following source-of-truth rules are explicit: - - * item visuals come from the canonical visual registry. - * UI icons are previews, not independent art. - * tool categories come from the tool registry. - * item effects come from EffectRegistry. - * diseases come from DiseaseRegistry. - * food behavior comes from FoodRegistry. - * rain visuals are separate from rain-spawned water items. - * zunchi is intentionally unchanged. - * no field balance, save/load, or debug scenario implementation in this pass. -* Avoid many small docs. Prefer a small set such as: - - * `docs/ARCHITECTURE.md` - * `docs/CONTENT_GUIDE.md` - * `docs/MAINTENANCE.md` -* Remove obsolete docs if safely redundant. -* Do not delete `docs/prompt.txt`. - -15. Preserve user-facing Japanese UI text unless intentionally specified. - -* Game UI remains Japanese. -* Docs are English. -* The Codex implementation may use English comments for architecture, but visible labels/tooltips remain Japanese. - -16. Regression fixes to preserve. - Do not regress the following existing fixes: - -* Removed unwanted bubbles: - - * ドン - * ぐるる - * すっきり - * Hg xN - * ちまっ - * でかっ - * へにゃ - * ムキッ - * mm... -* Ball tool UI icon must be soccer ball emoji. -* Time periods: - - * morning starts at 05:00 - * noon/day starts at 10:00 - * evening starts at 17:00 - * night starts at 20:00 -* Genkotsu: - - * stronger knockback for living things - * zunchi is knocked away - * damaged Tarinai gain fear and lose openness -* Rain visual: - - * diagonal angled line rain, not droplets. -* Rain-spawned water item / zunda juice / mercury: - - * horizontal oval item visuals. -* Sleeping Tarinai: - - * can be carried by ants - * do not wake from ant carrying - * do not attack ants while sleeping - * after waking, remain awake for at least 10 seconds. -* Tarinai data: - - * fight win rate instead of cumulative defeats. -* Fight: - - * on taking damage, Tarinai may lose/flee probabilistically. - * high aggression lowers loss chance. - * high damage and low HP increase loss chance. - -17. Versioning and cache. - -* Bump app version to the next patch/minor version consistently. -* Update: - - * version file - * service worker cache name - * asset query versions - * manifest if present -* Ensure `service-worker.js` itself remains no-cache/no-store. -* Ensure generated app manifest validation still passes. - -18. Validation. - Run and report: - -* `node --check js/*.js service-worker.js` -* manifest validation/generation check if scripts exist -* zip integrity check if packaging -* basic static grep checks: - - * no stale app version references - * no removed bubble strings still emitted as bubbles - * mobile UI visibility logic uses the new InputModeManager - * tool categories are not duplicated in `index.html` - * sound metadata is not duplicated as canonical data in both `sound_pack.js` and `audio.js` - * item visual drift-prone items use canonical visual registry - * docs are English except `docs/prompt.txt` - -Deliverables: - -* Updated project files. -* Updated ZIP. -* Brief implementation summary. -* Validation results. -* Mention any deliberately deferred items: - - * field balance tuning - * save/load - * debug scenario modes - * zunchi expansion +Implement the new need-driven behavior system for the existing “tarinai” observation game. + +Keep the implementation simple, localized, and compatible with the existing architecture. Do not perform a broad rewrite unless absolutely necessary. + +Important source-code text rule: +All newly added Japanese UI strings or Japanese reason/action strings in source code must be written as Unicode escape sequences, not raw Japanese characters. + +Example: +Do not write: +"あぶないけど、食べた。" + +Write: +"\u3042\u3076\u306a\u3044\u3051\u3069\u3001\u98df\u3079\u305f\u3002" + +Runtime text may display Japanese, but source literals must be escaped. + +============================================================ +GOAL +============================================================ + +Replace or absorb the existing detailed emotion-driven behavior system into a simple six-need system. + +Behavior should be selected from six needs: + +- food +- sleep +- health +- safety +- social +- fulfill + +The system should allow imperfect behavior. + +Example: +If safety and food are both maxed, the tarinai may randomly choose food and eat even though it is dangerous. + +============================================================ +1. SIX NEEDS +============================================================ + +Each tarinai should have: + +needs = { + food: 0, + sleep: 0, + health: 0, + safety: 0, + social: 0, + fulfill: 0 +}; + +Meaning: + +food: +- eating +- drinking + +sleep: +- sleep +- rest +- tiredness + +health: +- illness +- injury +- dirt +- poison +- recovery + +safety: +- danger +- fear +- ants +- explosions +- punches +- being attacked + +social: +- friends +- parent/child +- mating/reproduction +- enemies if existing relation logic supports it + +fulfill: +- play +- owned place +- owned structure +- grass bed +- plushie +- simple construction + +Each need is internally 0–100. + +After raw calculation, quantize each value to 10-point steps: + +0, 10, 20, ... 100 + +Use a helper like: + +function quantizeNeed(value) { + return Math.max(0, Math.min(100, Math.round(value / 10) * 10)); +} + +For UI display, show only the tens digit: + +0, 1, 2, ... 10 + +Example: +internal value 80 -> display 8 +internal value 100 -> display 10 + +Safety is capped at 100 like every other need. +Safety is not a hard interrupt. + +============================================================ +2. NEED CALCULATION +============================================================ + +Calculate needs from existing tarinai/world state where possible. + +Suggested mapping: + +food: +- hunger +- thirst if available + +sleep: +- low energy +- long awake time if available +- night/time-of-day bonus if available + +health: +- disease +- injury +- dirtiness +- poison or negative status if available + +safety: +- nearby ants +- nearby dangerous items +- recent damage +- fear/panic-related existing state if any +- being attacked +- owned structure destruction shock + +social: +- loneliness if available +- nearby friend / parent / child +- reproduction readiness +- enemy proximity if current relation system supports it + +fulfill: +- wants to play +- has no owned structure +- wants to return to owned grass bed +- wants to carry/use plushie +- wants to build a simple owned structure + +Use existing personality fields if available: + +aggression: +- safety rises slightly less from danger +- may choose intimidate instead of panic when there is a breaker/attacker + +openness: +- fulfill rises more easily +- play/build actions become more likely + +sociability: +- social rises more easily +- reacts less negatively when others use owned structures + +neuroticism: +- safety and health rise more easily +- owned structure damage/destruction has stronger effect + +Keep personality modifiers small and easy to tune. + +============================================================ +3. ACTION SELECTION +============================================================ + +Use this behavior flow: + +1. Calculate all six raw needs. +2. Quantize all needs. +3. Find the maximum need value. +4. Collect all needs equal to the maximum. +5. Randomly choose one need from that tied top set. +6. Choose an executable action associated with that chosen need. +7. Store the chosen need and action in tarinai.intent. +8. Highlight only the chosen need in the tarinai data UI. + +If safety and food are both 100, either may be chosen randomly. + +Add helpers: + +- createDefaultNeeds() +- quantizeNeed(value) +- updateNeeds(tarinai, world) +- chooseTopNeedRandom(needs) +- chooseActionForNeed(need, tarinai, world) +- buildReasonText(chosenNeed, tiedNeeds, action) +- getNeedDisplayValue(value) + +============================================================ +4. SIMPLE ACTION DEFINITIONS +============================================================ + +Use a simple action list, not a complex behavior tree. + +Each action should have: + +- id +- need +- label +- phrase +- weight +- condition(tarinai, world) +- run(tarinai, world) + +Example shape: + +const TARINAI_ACTIONS = [ + { + id: "eat_food", + need: "food", + label: "\u98df\u3079\u7269\u3092\u63a2\u3057\u3066\u3044\u308b", + phrase: "\u98df\u3079\u305f", + weight: 50, + condition(t, world) { + return !!findNearestItemWithRole(world, t, "food"); + }, + run(t, world) { + const item = findNearestItemWithRole(world, t, "food"); + moveToOrUse(t, item); + } + } +]; + +Suggested actions: + +food: +- eat_food +- drink_water + +sleep: +- sleep_in_bed +- sleep_in_owned_structure +- sleep_anywhere + +health: +- use_medicine +- wash_or_drink_water +- rest_to_recover + +safety: +- flee +- hide_in_nest +- hide_at_owned_structure + +social: +- approach_friend +- approach_parent_or_child +- approach_mate +- intimidate_enemy + +fulfill: +- play +- wander_lightly +- build_grass_bed +- build_plushie +- return_owned_structure +- use_plushie + +Use weighted random among executable actions for the chosen need. + +If no action is executable, fall back to idle, wander, or rest. + +Do not make tarinai perfectly optimal. + +============================================================ +5. TIE REASON TEXT +============================================================ + +If multiple needs are tied for highest and the chosen need is only one of them, generate: + +“[ignored need phrase]\u3051\u3069\u3001[chosen action phrase]\u3002” + +Examples: +- "\u3042\u3076\u306a\u3044\u3051\u3069\u3001\u98df\u3079\u305f\u3002" +- "\u306d\u3080\u3044\u3051\u3069\u3001\u4ef2\u9593\u306b\u8fd1\u3065\u3044\u305f\u3002" +- "\u304a\u306a\u304b\u304c\u3059\u3044\u3066\u3044\u308b\u3051\u3069\u3001\u81ea\u5206\u306e\u5bdd\u5e8a\u3078\u623b\u3063\u305f\u3002" +- "\u8abf\u5b50\u304c\u60aa\u3044\u3051\u3069\u3001\u904a\u3093\u3060\u3002" + +When multiple ignored needs exist, mention the ignored need with highest priority: + +safety > health > food > sleep > social > fulfill + +Conflict phrases: + +food: +"\u304a\u306a\u304b\u304c\u3059\u3044\u3066\u3044\u308b" + +sleep: +"\u306d\u3080\u3044" + +health: +"\u8abf\u5b50\u304c\u60aa\u3044" + +safety: +"\u3042\u3076\u306a\u3044" + +social: +"\u3060\u308c\u304b\u304c\u6c17\u306b\u306a\u308b" + +fulfill: +"\u81ea\u5206\u306e\u5834\u6240\u304c\u6c17\u306b\u306a\u308b" + +If there is no tie, use: + +“[need phrase]\u306e\u3067\u3001[action phrase]\u3002” + +Store: + +tarinai.intent = { + need: chosenNeed, + tiedNeeds, + actionId: action.id, + actionLabel: action.label, + reasonText +}; + +============================================================ +6. NEED UI +============================================================ + +Update the tarinai data UI. + +Show six needs as 0–10 values. + +Labels must be escaped in source: + +food label: +"\u6442\u990c" + +sleep label: +"\u7761\u7720" + +health label: +"\u5065\u5eb7" + +safety label: +"\u5b89\u5168" + +social label: +"\u95a2\u4fc2" + +fulfill label: +"\u5145\u8db3" + +Example UI: + +摂餌 8 +睡眠 3 +健康 1 +安全 10 +関係 4 +充足 10 ★ + +Only the need actually chosen for the current action receives the highlight. + +Also show: + +"\u3044\u307e": +[action label] + +"\u7406\u7531": +[reasonText] + +Do not show detailed need breakdowns. +Do not add graphs or extra panels. + +============================================================ +7. ITEM ROLES AND NEED EFFECTS +============================================================ + +Use minimal item roles and needEffects. + +Do not create a broad tag system. + +Item example: + +item.roles = { + food: true, + drink: true, + medicine: true, + sleepPlace: true, + danger: true, + grassMaterial: true +}; + +item.needEffects = { + food: 0, + sleep: 0, + health: 0, + safety: 0, + social: 0, + fulfill: 0 +}; + +Only add roles that are actually needed by the new behavior. + +Useful helpers: + +- findNearestItemWithRole(world, tarinai, role) +- findNearestSleepPlace(world, tarinai) +- findNearbyDanger(world, tarinai) +- findNearbyMaterial(world, tarinai, materialRole) + +Adapt to existing item registries where possible. + +============================================================ +8. STRUCTURE REGISTRY +============================================================ + +Keep StructureRegistry because tarinai-built structures will expand in the future. + +Do not collapse structures into one-off special item cases. + +Create or adapt a small StructureRegistry for buildable tarinai structures. + +Shared structure instance shape: + +{ + id, + type, + isStructure: true, + ownerId, + hp, + attachment, + usedCount, + x, + y, + roles, + needEffects +} + +Do not implement: +- repair +- inheritance +- ownership privacy +- material-carrying inventory +- complex construction logistics + +First buildable structures: + +- grass_bed +- plushie + +============================================================ +9. STRUCTURE: GRASS BED +============================================================ + +Structure type: +"grass_bed" + +Japanese label, escaped: +"\u8349\u306e\u7c21\u6613\u30d9\u30c3\u30c9" + +Concept: +A simple bed made from grass. It is an owned place. The owner prefers it for sleep, safety, and fulfill. + +Example registry entry shape: + +grass_bed: { + type: "grass_bed", + label: "\u8349\u306e\u7c21\u6613\u30d9\u30c3\u30c9", + buildNeed: "fulfill", + buildTime: 4, + maxHp: 100, + materials: { + grassMaterial: 1 + }, + roles: { + sleepPlace: true, + ownedStructure: true + }, + needEffects: { + food: 0, + sleep: 60, + health: 5, + safety: 25, + social: 0, + fulfill: 40 + }, + create(owner, x, y, world) { + return { + id: createId("structure"), + type: "grass_bed", + isStructure: true, + ownerId: owner.id, + hp: 100, + attachment: 20, + usedCount: 0, + x, + y, + roles: this.roles, + needEffects: this.needEffects + }; + }, + onUse(user, structure, world) { + // owner gets stronger effects + // non-owner gets weaker effects + // owner use increases attachment + }, + onDestroyed(structure, world, breaker) { + // increase owner safety and fulfill + // trigger panic or intimidate through need shock logic + } +} + +Build condition: +- chosen need is fulfill +- tarinai has no owned grass_bed +- grass material is nearby +- tarinai is not sleeping, fighting, or panicking + +Build process: +- move near grass +- spend short build time if existing state system supports it +- consume/reduce grass if easy +- create grass_bed through StructureRegistry + +Owner behavior: +- owner prefers own grass_bed for sleep, safety, and fulfill +- using own grass_bed reduces sleep, safety, and fulfill +- using own grass_bed increases attachment + +Other tarinai: +- may use it with weaker effects +- if owner sees another tarinai using it: + - aggression may cause intimidate + - neuroticism may increase safety/fulfill + - sociability reduces negative reaction + +Destruction: +- hp can be reduced by explosions, punches, weather, repeated use, or existing damage sources if easy to connect +- when hp reaches 0, call onDestroyed and remove structure + +============================================================ +10. STRUCTURE: PLUSHIE +============================================================ + +Add a new tarinai-built structure: + +type: +"plushie" + +Japanese label, escaped: +"\u306c\u3044\u3050\u308b\u307f" + +Concept: +A small plushie item that resembles a tarinai. It is made from grass. When completed, it attaches to the owner tarinai’s head. While attached, it reduces fulfill. If damaged, it breaks and disappears. The owner receives a strong need shock and enters panic or intimidate. + +Example registry entry shape: + +plushie: { + type: "plushie", + label: "\u306c\u3044\u3050\u308b\u307f", + buildNeed: "fulfill", + buildTime: 4, + maxHp: 1, + materials: { + grassMaterial: 1 + }, + roles: { + carriedObject: true, + ownedStructure: true, + fulfillObject: true + }, + needEffects: { + food: 0, + sleep: 0, + health: 0, + safety: 5, + social: 0, + fulfill: 50 + }, + create(owner, x, y, world) { + return { + id: createId("structure"), + type: "plushie", + isStructure: true, + ownerId: owner.id, + hp: 1, + attachment: 30, + usedCount: 0, + x, + y, + carriedById: owner.id, + onHead: true, + roles: this.roles, + needEffects: this.needEffects + }; + }, + onUse(user, structure, world) { + // if owner carries/uses it, reduce fulfill + // optionally reduce safety slightly + // increase attachment slightly + }, + onDestroyed(structure, world, breaker) { + // large shock to owner safety and fulfill + // trigger panic or intimidate + } +} + +Build condition: +- chosen need is fulfill +- tarinai does not already own/carry a plushie +- grass material is nearby +- tarinai is not sleeping, fighting, or panicking + +Build process: +- move near grass +- spend short build time if existing state system supports it +- consume/reduce grass if easy +- create plushie through StructureRegistry +- attach it to owner’s head + +Behavior while attached: +- follow owner position +- render above owner’s head +- use same or similar sprite as tarinai, scaled down +- reduce fulfill over time or when used +- optionally reduce safety slightly +- do not implement inventory + +Damage/destruction: +- any meaningful damage destroys it +- remove plushie +- increase owner safety and fulfill strongly +- trigger panic or intimidate through need shock logic + +Do not implement: +- repair +- inheritance +- trading +- inventory +- multiple plushies per tarinai + +============================================================ +11. EMOTION SYSTEM SIMPLIFICATION +============================================================ + +Remove the old detailed emotion system as a behavior driver. + +Behavior must be selected only from the six needs: +food, sleep, health, safety, social, fulfill. + +Old emotions should be removed or absorbed: + +fear -> safety +loneliness -> social +happiness -> low stress / low fulfill pressure +sadness -> fulfill/social/safety pressure +comfort -> sleep/safety/fulfill satisfaction +boredom -> do not implement +anger -> intimidate state only +panic -> need shock reaction +stress -> derived pressure from needs + +Do not keep happiness, sadness, fear, loneliness, comfort, boredom, or anger as independent behavior-driving values. + +============================================================ +12. STRESS REDEFINITION +============================================================ + +Stress is not an independent emotion. + +Stress is a derived value calculated from current need pressure. + +Do not directly add to stress for shock events. +For shock events, increase relevant needs first, then recalculate stress from needs. + +Stress must not be used as a primary action-selection need. + +Behavior is selected only from the six needs. + +Stress may affect: +- expression +- minor visual intensity +- UI display if already present +- minor secondary effects if existing systems need it + +Suggested pressure function: + +function needPressure(value) { + const x = value / 100; + return x * x * 100; +} + +Suggested stress calculation: + +stress = + needPressure(food) * 0.10 + + needPressure(sleep) * 0.12 + + needPressure(health) * 0.25 + + needPressure(safety) * 0.30 + + needPressure(social) * 0.08 + + needPressure(fulfill) * 0.15; + +Adjust weights if needed, but keep stress derived from needs. + +============================================================ +13. PANIC REDEFINITION +============================================================ + +Panic is not a need. +Panic is not a persistent emotion. + +Panic is a short temporary reaction state caused by large sudden increases in safety, health, or fulfill. + +Food, sleep, and social should not normally trigger panic. + +Track previous needs or otherwise compute need delta. + +Suggested rule: + +panic triggers if: +- safety increases suddenly by 40 or more +- health increases suddenly by 45 or more +- fulfill increases suddenly by 50 or more + +Panic should last for a short timer, such as 2–4 seconds. + +After panic timer ends, return to normal need-based action selection. + +If panic would be triggered and the tarinai has high aggression and a known breaker/attacker, use intimidate instead of panic. + +Example: + +if (shockTriggered) { + if (breaker && t.personality?.aggression > 0.6) { + t.state = "intimidate"; + t.target = breaker; + } else { + t.state = "panic"; + t.panicTimer = 3.0; + } +} + +============================================================ +14. EXPRESSION / VISUAL EMOTION COMPATIBILITY +============================================================ + +If the old emotion system is deeply tied to expressions, keep only a small compatibility layer for visuals. + +Expressions should be derived from: +- current state +- chosen need +- stress level +- panic/intimidate + +Suggested mapping: + +state panic: +panic expression + +state intimidate: +angry/threat expression + +chosen need safety: +worried expression + +chosen need food: +hungry expression + +chosen need sleep: +sleepy expression + +chosen need health: +unwell expression + +chosen need social: +social/looking expression + +chosen need fulfill: +neutral/pleased expression + +Do not let old expression emotions drive behavior. + +============================================================ +15. SAVE COMPATIBILITY +============================================================ + +Backward compatibility is not required. + +Do not implement save migrations. +Do not add compatibility shims for old saves unless the current code would immediately crash during normal startup. + +It is acceptable if old saves are incompatible after this feature. + +============================================================ +16. DO NOT ADD +============================================================ + +Do not add: +- long-term memory +- boredom/habit system +- player-intervention profile +- ReactionRegistry +- WorldRules +- full behavior tree +- complex utility AI +- detailed need breakdown UI +- repair system +- inheritance system +- material-carrying inventory +- structure privacy system + +============================================================ +17. ACCEPTANCE CRITERIA +============================================================ + +After implementation: + +- Each tarinai has six needs: + - food + - sleep + - health + - safety + - social + - fulfill + +- Needs are clamped 0–100. +- Needs are quantized to 10-point steps. +- UI displays needs as 0–10. +- Only the chosen action-driving need is highlighted. +- If multiple needs are tied for highest, one is chosen randomly. +- Safety does not force interruption. +- If safety and another need are tied, non-safety behavior can happen. +- Tie reason text uses the “Xけど、Yした。” format. +- Newly added Japanese source strings are Unicode escaped. +- Actions are defined in a simple action list. +- Items expose minimal roles and needEffects. +- StructureRegistry exists and supports at least grass_bed and plushie. +- grass_bed consumes grass to build. +- grass_bed is preferred by its owner. +- grass_bed destruction increases owner safety/fulfill and can trigger panic/intimidate. +- plushie consumes grass to build. +- plushie attaches to the owner’s head. +- plushie visually resembles a small tarinai. +- plushie reduces fulfill while carried/used. +- plushie breaks and disappears when damaged. +- plushie destruction strongly increases owner safety/fulfill and triggers panic/intimidate. +- Old detailed emotion values no longer drive behavior. +- Stress is derived from needs. +- Panic is caused by sudden safety/health/fulfill increases. +- Old save compatibility is not required. \ No newline at end of file diff --git a/index.html b/index.html index 75ac774..a7e7257 100644 --- a/index.html +++ b/index.html @@ -5,11 +5,11 @@