"use strict"; function escapeHtml(value) { return window.TarinaiUIHelpers.htmlEscape(value); } function loadLogPushSettings() { try { const raw = localStorage.getItem("tarinai_log_push_settings_v2"); if (!raw) return; const parsed = JSON.parse(raw); uiCache.logPushEnabled = Boolean(parsed.enabled); if (Array.isArray(parsed.kinds)) uiCache.logPushKinds = new Set(parsed.kinds); } catch (_) {} } function saveLogPushSettings() { try { localStorage.setItem("tarinai_log_push_settings_v2", JSON.stringify({ enabled: Boolean(uiCache.logPushEnabled), kinds: Array.from(uiCache.logPushKinds || []), })); } catch (_) {} } function syncLogPushControls() { if (ui.logPushEnabled) ui.logPushEnabled.checked = Boolean(uiCache.logPushEnabled); for (const input of ui.logPushControls?.querySelectorAll("[data-push-kind]") || []) { input.checked = uiCache.logPushKinds?.has(input.dataset.pushKind || "") ?? false; } } function syncAudioControls() { if (!window.TarinaiAudio) return; for (const input of ui.soundCategoryControls?.querySelectorAll("[data-sound-category]") || []) { const category = input.dataset.soundCategory || ""; input.checked = audio.categoryOn ? audio.categoryOn(category) : true; input.disabled = !audio.enabled; } if (ui.soundMasterToggle) ui.soundMasterToggle.checked = Boolean(audio.enabled); if (ui.soundBtn) { ui.soundBtn.textContent = audio.enabled ? "\u97f3 ON" : "\u97f3 OFF"; ui.soundBtn.classList.toggle("active", Boolean(audio.enabled)); ui.soundBtn.setAttribute("aria-expanded", ui.soundPanel && !ui.soundPanel.classList.contains("hidden") ? "true" : "false"); } } function closeSoundPanel() { ui.soundPanel?.classList.add("hidden"); syncAudioControls(); } function toggleSoundPanel() { if (audio.enabled) audio.uiClick?.(); ui.soundPanel?.classList.toggle("hidden"); syncAudioControls(); } function pushLogNotification(entry = {}) { if (!uiCache.logPushEnabled || !entry || entry.hiddenFromObservation) return; const kind = entry.kind || "note"; if (!uiCache.logPushKinds?.has(kind)) return; const overlay = ui.logPushOverlay; if (!overlay) return; audio.notify?.(); const card = document.createElement("div"); card.className = `log-push-toast log-push-${kind}`; const tag = document.createElement("span"); tag.className = "log-push-tag"; tag.textContent = logKindLabel(kind); const time = document.createElement("span"); time.className = "log-push-time"; time.textContent = formatLogTime(entry.time || 0); const text = document.createElement("div"); text.className = "log-push-text"; text.textContent = formatLogDisplayText(entry.text || ""); card.appendChild(tag); card.appendChild(time); card.appendChild(text); overlay.prepend(card); while (overlay.children.length > 5) overlay.lastElementChild?.remove(); window.setTimeout(() => { card.classList.add("leaving"); window.setTimeout(() => card.remove(), 220); }, 5200); } window.pushLogNotification = pushLogNotification; function shouldShowInEventLog(entry = {}) { if (!entry || entry.hiddenFromObservation) return false; const type = String(entry.eventType || ""); const text = String(entry.text || ""); if (type === "player_item_placement" || type.includes("player") || type.includes("tool") || type.includes("robot")) return false; if (/\u30ed\u30dc\u6383\u9664\u6a5f|\u6383\u9664\u6a5f/.test(text)) return false; return true; } function renderLog(logs) { ui.log.innerHTML = ""; const frag = document.createDocumentFragment(); const touchFirst = Boolean(window.TarinaiInputMode.classification?.touchFirst || document.body.classList.contains("touch-mobile-ui") || window.innerWidth <= 980); const limit = touchFirst ? 34 : 80; const visibleLogs = Array.isArray(logs) ? logs.map(raw => typeof raw === "string" ? { time: world.time, text: raw, kind: "note" } : raw).filter(shouldShowInEventLog) : []; const rows = visibleLogs.slice(0, limit); for (const entry of rows) { const kind = entry.kind || "note"; const div = document.createElement("div"); div.className = `log-entry log-${kind}`; const tag = document.createElement("span"); tag.className = "log-tag"; tag.textContent = logKindLabel(kind); const time = document.createElement("span"); time.className = "time"; time.textContent = formatLogTime(entry.time || 0); div.appendChild(tag); div.appendChild(time); div.append(document.createTextNode(formatLogDisplayText(entry.text || ""))); frag.appendChild(div); } ui.log.appendChild(frag); } function formatLogTime(timeValue) { const t = Math.max(0, Number(timeValue) || 0); const day = Math.floor(t / CONFIG.dayLength) + 1; const dayT = ((t % CONFIG.dayLength) + CONFIG.dayLength) % CONFIG.dayLength; const totalMinutes = Math.floor(dayT / CONFIG.dayLength * 24 * 60); const hh = String(Math.floor(totalMinutes / 60)).padStart(2, "0"); const mm = String(totalMinutes % 60).padStart(2, "0"); return `${day}\u65e5 ${hh}\u6642${mm}\u5206`; } function logKindLabel(kind) { return { birth: "\u8a95\u751f", death: "\u6b7b\u4ea1", fight: "\u55a7\u5629", food: "\u98df\u4e8b", grass: "\u8349", weather: "\u74b0\u5883", relation: "\u95a2\u4fc2", accident: "\u4e8b\u6545", observe: "\u89b3\u5bdf", event: "\u51fa\u6765\u4e8b", note: "\u8a18\u9332" }[kind] || "\u8a18\u9332"; } function tarinaiSpritePathForId(id) { const live = world?.tarinai?.find(t => (t.id === id || t.familyKey === id) && !t.dead); const sid = live?.spriteId ? live.spriteId() : live?.type; const fam = world?.family?.[id]; const fallback = fam?.type; return (SPRITES.find(s => s.id === (sid || fallback)) || SPRITES[0]).path; } function relationIconHtml(id) { if (!id) return ""; return ``; } function relationEntries(t, kind = "friend") { const rows = []; const liveIds = new Set((world?.tarinai || []).filter(o => o && !o.dead && o !== t).map(o => o.id)); const ids = new Set(Object.keys(t?.relationships || {})); for (const other of world?.tarinai || []) { if (other && other !== t && other.id && other.relationships?.[t?.id]) ids.add(other.id); } for (const id of ids) { if (!liveIds.has(id)) continue; const rel = t?.relationships?.[id] || relationDefaults(); const other = world?.tarinai?.find(o => o && o.id === id) || null; const reverse = other?.relationships?.[t?.id] || null; const score = kind === "enemy" ? Math.max(rel.fear || 0, reverse?.fear || 0) : Math.max(rel.affinity || 0, reverse?.affinity || 0); const threshold = kind === "enemy" ? 0.5 : FRIEND_AFFINITY_THRESHOLD; if (score <= threshold) continue; rows.push({ id, score, name: relationDisplayName(world, id) }); } rows.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name, "ja")); return rows; } function relationListHtml(t, kind = "friend") { const rows = relationEntries(t, kind); if (!rows.length) return "\u306a\u3057"; const sign = kind === "friend" ? "+" : ""; return `
${rows.map(r => ` `).join("")}
`; } function focusTarinaiById(id) { const t = world?.tarinai?.find(o => o && !o.dead && (o.id === id || o.familyKey === id)); if (!t) { showToast("\u305d\u306e\u500b\u4f53\u306f\u3082\u3046\u9078\u629e\u3067\u304d\u307e\u305b\u3093\u3002"); return false; } window.TarinaiCommands.dispatch(world, { type: "selection.focus", target: t, options: { pulse: 1.25 } }); uiCache.selectedSnapshot = ""; renderSelected(); renderStats(); render?.(); showToast(`\u300c${t.name}\u300d\u3078\u79fb\u52d5\u3057\u307e\u3057\u305f\u3002`); return true; }