diff --git a/game1/index.html b/game1/index.html new file mode 100644 index 0000000..0eb54dc --- /dev/null +++ b/game1/index.html @@ -0,0 +1,160 @@ + + + + + + + + + 林夏 + + + +
+ +
+

林夏

+
+ 今晚 16 条消息
+ 你接谁,不接谁
+ 决定明天的自己 +
+
+
操 作 说 明
+ +
+
来电时
+
单击 / 右滑接听
+
左滑 / 双击拒接
+
+ +
+
收到消息
+
单击播放
+
双击 / 左滑跳过
+
+ +
+
选择回复
+
单击简单回应
+
右滑温暖回应
+
左滑冷淡回应
+
上滑追问
+
下滑沉默
+
双击不回复
+
+ +
+
播放中
+
双击跳过
+
长按重播
+
+ +
+
随时可用
+
两指长按暂停
+
三指点击退出(暂停后)
+
长按播报未读数
+
+
+ +
· 轻触屏幕开始 ·
+
+ 建议关灯 · 戴上耳机
+ 按你的节奏来 +
+
+ 本游戏涉及孤独、家庭关系等情感话题
+ 请在舒适的状态下体验 +
+
+ +
+
+
+ + + + + + + + + + + diff --git a/game1/js/audio.js b/game1/js/audio.js new file mode 100644 index 0000000..50b5c27 --- /dev/null +++ b/game1/js/audio.js @@ -0,0 +1,283 @@ +// audio.js — 音频管理器 + 合成 UI 音效 + +class AudioManager { + constructor() { + this._ctx = null; + this._master = null; + this._voiceQueue = []; + this._voiceEl = null; + this._ringEl = null; + this._bgmEl = null; + this._ambEl = null; + this._preloaded = {}; + } + + // ── 初始化(必须在用户手势后调用)── + async init() { + this._ctx = new (window.AudioContext || window.webkitAudioContext)(); + if (this._ctx.state === 'suspended') await this._ctx.resume(); + this._master = this._ctx.createGain(); + this._master.gain.value = 1.0; + this._master.connect(this._ctx.destination); + } + + // ── 合成短音(UI 反馈音效)── + synth({ freq = 440, freq2 = null, dur = 100, type = 'sine', vol = 0.3 } = {}) { + if (!this._ctx) return; + const t = this._ctx.currentTime; + const d = dur / 1000; + + const osc = this._ctx.createOscillator(); + const gain = this._ctx.createGain(); + + osc.type = type; + osc.frequency.setValueAtTime(freq, t); + if (freq2 != null) { + osc.frequency.linearRampToValueAtTime(freq2, t + d); + } + + gain.gain.setValueAtTime(vol, t); + gain.gain.setValueAtTime(vol, t + d * 0.75); + gain.gain.linearRampToValueAtTime(0, t + d); + + osc.connect(gain); + gain.connect(this._master); + osc.start(t); + osc.stop(t + d + 0.05); + } + + // ── 预加载短音效 ── + async preload(key, url) { + if (this._preloaded[key]) return; + try { + const res = await fetch(url); + const buf = await res.arrayBuffer(); + this._preloaded[key] = await this._ctx.decodeAudioData(buf); + } catch (e) { + console.warn('[Audio] preload failed:', key, e); + } + } + + // ── 播放预加载音效 ── + playFX(key, { vol = 1.0, loop = false } = {}) { + const buf = this._preloaded[key]; + if (!buf) return null; + const src = this._ctx.createBufferSource(); + src.buffer = buf; + src.loop = loop; + const gain = this._ctx.createGain(); + gain.gain.value = vol; + src.connect(gain); + gain.connect(this._master); + src.start(); + return { src, gain, stop: () => { try { src.stop(); } catch (_) {} } }; + } + + // ── 铃声(循环)── + async startRingtone(url) { + this.stopRingtone(); + this._ringEl = new Audio(url); + this._ringEl.loop = true; + this._ringEl.volume = 1.0; + try { await this._ringEl.play(); } catch (e) { console.warn('[Audio] ring error', e); } + } + + stopRingtone() { + if (this._ringEl) { + this._ringEl.pause(); + this._ringEl.src = ''; + this._ringEl = null; + } + } + + // ── 语音播放(多段顺序)── + playVoice(urls, { vol = 1.0, onEnd = null } = {}) { + this.stopVoice(); + this._voiceQueue = [...urls]; + this._playNext(vol, onEnd); + } + + _playNext(vol, onEnd) { + if (this._voiceQueue.length === 0) { + this._voiceEl = null; + if (onEnd) onEnd(); + return; + } + const url = this._voiceQueue.shift(); + const el = new Audio(url); + el.volume = vol; + this._voiceEl = el; + el.onended = () => this._playNext(vol, onEnd); + el.onerror = () => { + console.warn('[Audio] voice error:', url); + this._playNext(vol, onEnd); + }; + el.play().catch(e => console.warn('[Audio] play error', e)); + } + + stopVoice() { + this._voiceQueue = []; + if (this._voiceEl) { + this._voiceEl.onended = null; + this._voiceEl.pause(); + this._voiceEl = null; + } + } + + isVoicePlaying() { + return !!(this._voiceEl && !this._voiceEl.paused); + } + + // ── BGM(淡入淡出切换)── + async startBGM(url, { vol = 0.35, fade = 2000 } = {}) { + if (this._bgmEl) { + const old = this._bgmEl; + this._fadeOut(old, fade / 2).then(() => { old.pause(); old.src = ''; }); + } + const el = new Audio(url); + el.loop = true; + el.volume = 0; + this._bgmEl = el; + try { + await el.play(); + this._fadeTo(el, vol, fade); + } catch (e) { console.warn('[Audio] BGM error', e); } + } + + stopBGM(fade = 2000) { + if (this._bgmEl) { + const el = this._bgmEl; + this._bgmEl = null; + this._fadeOut(el, fade).then(() => { el.pause(); el.src = ''; }); + } + } + + // ── 环境音 ── + async startAmbience(url, { vol = 0.25 } = {}) { + if (this._ambEl) { this._ambEl.pause(); this._ambEl.src = ''; } + const el = new Audio(url); + el.loop = true; + el.volume = vol; + this._ambEl = el; + try { await el.play(); } catch (e) { console.warn('[Audio] ambience error', e); } + } + + stopAmbience() { + if (this._ambEl) { this._ambEl.pause(); this._ambEl.src = ''; this._ambEl = null; } + } + + // ── 音量渐变 ── + _fadeTo(el, target, duration) { + const start = el.volume; + const steps = 30; + const dt = duration / steps; + const dv = (target - start) / steps; + let i = 0; + const t = setInterval(() => { + el.volume = Math.max(0, Math.min(1, start + dv * i)); + if (++i >= steps) clearInterval(t); + }, dt); + } + + _fadeOut(el, duration) { + return new Promise(resolve => { + const start = el.volume; + const steps = 20; + const dt = duration / steps; + const dv = start / steps; + let i = 0; + const t = setInterval(() => { + el.volume = Math.max(0, start - dv * i); + if (++i >= steps) { clearInterval(t); resolve(); } + }, dt); + }); + } +} + +const Snd = new AudioManager(); + +// ══════════════════════════════════════════════════ +// SFX_UI — 合成 UI 音效(不依赖音频文件) +// ══════════════════════════════════════════════════ + +const SFX_UI = { + // 确认操作(单击) + tap() { + Snd.synth({ freq: 880, dur: 45, vol: 0.2 }); + }, + + // 滑动确认 + swipe() { + Snd.synth({ freq: 660, dur: 60, vol: 0.18 }); + }, + + // 无效操作 + error() { + Snd.synth({ freq: 200, dur: 100, type: 'square', vol: 0.1 }); + }, + + // 新消息到达 + notify() { + Snd.synth({ freq: 523, dur: 100, vol: 0.25 }); + setTimeout(() => Snd.synth({ freq: 659, dur: 130, vol: 0.2 }), 130); + }, + + // 进入选择模式(三音上行) + choiceReady() { + Snd.synth({ freq: 440, dur: 80, type: 'triangle', vol: 0.18 }); + setTimeout(() => Snd.synth({ freq: 523, dur: 80, type: 'triangle', vol: 0.18 }), 100); + setTimeout(() => Snd.synth({ freq: 659, dur: 120, type: 'triangle', vol: 0.18 }), 200); + }, + + // 选择:温暖/接受(右滑)— 上行音 + choiceWarm() { + Snd.synth({ freq: 440, freq2: 659, dur: 140, vol: 0.22 }); + }, + + // 选择:冷淡/拒绝(左滑)— 下行音 + choiceCold() { + Snd.synth({ freq: 523, freq2: 349, dur: 140, vol: 0.22 }); + }, + + // 选择:好奇/追问(上滑)— 快速上行 + choiceCurious() { + Snd.synth({ freq: 523, freq2: 784, dur: 120, vol: 0.22 }); + }, + + // 选择:沉默/退缩(下滑)— 极轻低音 + choiceSilent() { + Snd.synth({ freq: 330, dur: 200, vol: 0.08 }); + }, + + // 跳过 / 忽略 + skip() { + Snd.synth({ freq: 587, freq2: 392, dur: 80, vol: 0.12 }); + }, + + // 下一条消息即将到来 + next() { + Snd.synth({ freq: 440, dur: 80, vol: 0.1 }); + setTimeout(() => Snd.synth({ freq: 523, dur: 100, vol: 0.13 }), 120); + }, + + // 打字/录音音效(~800ms) + typing() { + for (let i = 0; i < 6; i++) { + setTimeout(() => { + Snd.synth({ freq: 600 + Math.random() * 200, dur: 30, type: 'sine', vol: 0.1 }); + }, i * 120); + } + }, + + // 发送音效 + send() { + Snd.synth({ freq: 400, freq2: 900, dur: 120, type: 'sine', vol: 0.18 }); + }, + + // 结局音效 + ending() { + Snd.synth({ freq: 523, dur: 400, vol: 0.25 }); + setTimeout(() => Snd.synth({ freq: 659, dur: 400, vol: 0.2 }), 450); + setTimeout(() => Snd.synth({ freq: 784, dur: 600, vol: 0.15 }), 900); + }, +}; diff --git a/game1/js/engine.js b/game1/js/engine.js new file mode 100644 index 0000000..6915907 --- /dev/null +++ b/game1/js/engine.js @@ -0,0 +1,825 @@ +// engine.js — 游戏引擎 v2(多轮对话 + 林夏语音 + NPC反应) +// +// 状态流:idle → notification/ringing → playing → choosing +// → responding → reacting → [choosing | idle] → …… → ending +// +// 新增状态: +// responding — 林夏说话中(打字音效 + 语音播放) +// reacting — NPC反应播放中 +// paused — 游戏暂停(两指长按触发) + +class GameEngine { + constructor() { + this._state = 'idle'; + + // 剧情变量 + this.vars = { + MOM_LINK: false, + HE_BACK: null, + GROUP_REPLY: false, + ZHOUNAN_DEPTH: 0, + ZHOUNAN_SHARE: false, + SELF_RECORD: false, + UNREAD: 0, + REPLY_COUNT: 0, + }; + + this.profile = new ProfileTracker(); + this.msgState = {}; + this.currentMsg = null; + + this._queue = []; + this._endingTriggered = false; + this._reminderTimer = null; + + // v2: 对话系统 + this._currentChoices = null; // 当前可用的选项集 + this._pendingResolve = null; // 用于中断语音播放的 resolve + this._skipRequested = false; // 跳过标志 + + // 暂停系统 + this._pausedState = null; // 暂停前的状态 + + this.gest = null; + } + + // ── 状态 getter/setter ── + get state() { return this._state; } + set state(s) { + this._state = s; + dbg(`state: ${s}`); + const el = document.getElementById('hint'); + if (!el) return; + const H = { + idle: '', + notification: '单击 播放 · 双击 跳过', + ringing: '单击 接听 · 左滑 拒接', + playing: '双击 跳过 · 长按 重播', + choosing: '→温暖 ←冷淡 ↑追问 ↓沉默', + responding: '双击 跳过', + reacting: '双击 跳过', + paused: '单击 继续 · 三指点击 退出', + ending: '', + }; + el.textContent = H[s] || ''; + } + + // ══════════════════════════════════════════ + // 初始化 & 启动 + // ══════════════════════════════════════════ + + init(gestureDetector) { + this.gest = gestureDetector; + this.gest + .on('singletap', () => this._onTap()) + .on('doubletap', () => this._onDoubleTap()) + .on('swipe_left', () => this._onSwipe('left')) + .on('swipe_right', () => this._onSwipe('right')) + .on('swipe_up', () => this._onSwipe('up')) + .on('swipe_down', () => this._onSwipe('down')) + .on('longpress', () => this._onLongPress()) + .on('twofinger_longpress', () => this._onPause()) + .on('threefinger_tap', () => this._onExit()); + } + + async start() { + this._queue = [...MESSAGES]; + + // 内容预警 + await this._playVoiceAsync([`${T}/v2_sys_content_warning_wav_v1.mp3`]); + await sleep(1000); + + await Snd.startAmbience(AMBIENCE_DEFAULT, { vol: 0.15 }); + await sleep(1500); + Snd.startBGM(`${MUS}/lv11_bgm_m1_main_loop_v1.mp3`, { vol: 0.1 }); + await sleep(1500); + + this._next(); + } + + // ══════════════════════════════════════════ + // 语音播放(异步 + 可中断) + // ══════════════════════════════════════════ + + _playVoiceAsync(urls) { + return new Promise(resolve => { + this._pendingResolve = resolve; + Snd.playVoice(urls, { + onEnd: () => { + this._pendingResolve = null; + resolve(); + }, + }); + }); + } + + _interruptVoice() { + Snd.stopVoice(); + TTS.stop(); + if (this._pendingResolve) { + this._pendingResolve(); + this._pendingResolve = null; + } + } + + // 打字 + 发送音效 + async _playTypingSend() { + SFX_UI.typing(); + await sleep(800); + if (this._skipRequested) return; + SFX_UI.send(); + await sleep(300); + } + + // ══════════════════════════════════════════ + // 消息队列推进 + // ══════════════════════════════════════════ + + async _next() { + if (this._endingTriggered) return; + + const msg = this._queue.shift(); + if (!msg) { + this.triggerFinalEnding(); + return; + } + + if (msg.requiresMomLink && !this.vars.MOM_LINK) { + this.triggerFinalEnding(); + return; + } + + this.currentMsg = msg; + this._currentChoices = msg.choices || null; + this.msgState[msg.id] = 'unread'; + this.vars.UNREAD++; + + if (msg.type === 'call') { + this._startRinging(msg); + } else { + this._notifyMessage(msg); + } + } + + _notifyMessage(msg) { + this.state = 'notification'; + Haptic.message(); + SFX_UI.notify(); + this._startReminder(); + } + + async _startRinging(msg) { + this.state = 'ringing'; + Haptic.ring(); + await Snd.startRingtone(msg.ringtone); + this._startReminder(); + } + + // ══════════════════════════════════════════ + // 通话流程(异步) + // ══════════════════════════════════════════ + + async _answerCall(msg) { + Snd.stopRingtone(); + Haptic.stop(); + Haptic.confirm(); + SFX_UI.tap(); + this._clearReminder(); + + this.state = 'playing'; + this.msgState[msg.id] = 'read'; + this.vars.UNREAD = Math.max(0, this.vars.UNREAD - 1); + + if (msg.stateOnAnswer) this._applyState(msg.stateOnAnswer); + if (msg.profileOnAnswer) this.profile.add(msg.profileOnAnswer); + + this._skipRequested = false; + + // 播放通话内容 + await this._playVoiceAsync(msg.audio); + + // _onDoubleTap 在 'playing' 状态下会直接处理状态转换 + // 所以如果状态已不是 'playing',说明跳过已被处理,直接返回 + if (this.state !== 'playing') return; + + // 自动挂断(MSG-08 未知号码) + if (msg.autoHangup) { + if (msg.sfxAfter) { + const sfx = Array.isArray(msg.sfxAfter) ? msg.sfxAfter[0] : msg.sfxAfter; + await this._playVoiceAsync([sfx]); + if (this.state !== 'playing') return; + } + this._proceedToNext(); + return; + } + + // 自动回复(MSG-01/03/14 妈妈电话、外卖、妈妈第二次电话) + if (msg.autoReply) { + await this._playTypingSend(); + if (this.state !== 'playing') return; + + this.state = 'responding'; + await this._playVoiceAsync([msg.autoReply]); + + // 条件反应(MSG-14:先播前导语"真的没事?",再根据 MOM_LINK 播放不同反应) + if (!this._skipRequested && msg.autoReact) { + this.state = 'reacting'; + // 前导语(如"真的没事?") + if (msg.autoReactPreamble) { + await sleep(500); + if (!this._skipRequested) { + await this._playVoiceAsync([msg.autoReactPreamble]); + } + } + // 条件分支反应 + if (!this._skipRequested) { + const val = this.vars[msg.autoReact.condition]; + const reactUrl = val ? msg.autoReact['true'] : msg.autoReact['false']; + if (reactUrl) { + await sleep(400); + if (!this._skipRequested) { + await this._playVoiceAsync([reactUrl]); + } + } + } + } + this._proceedToNext(); + return; + } + + // 通话后有选择(MSG-11 阿哲) + if (msg.choices) { + this._enterChoosing(msg.choices); + return; + } + + this._proceedToNext(); + } + + _rejectCall(msg) { + Snd.stopRingtone(); + Haptic.reject(); + SFX_UI.skip(); + this._clearReminder(); + this.msgState[msg.id] = 'missed'; + if (msg.profileOnMiss) this.profile.add(msg.profileOnMiss); + this._proceedToNext(); + } + + // ══════════════════════════════════════════ + // 消息播放(异步) + // ══════════════════════════════════════════ + + async _playMessage(msg) { + this._clearReminder(); + this.state = 'playing'; + this.msgState[msg.id] = 'read'; + this.vars.UNREAD = Math.max(0, this.vars.UNREAD - 1); + + if (msg.bgm) Snd.startBGM(msg.bgm, { vol: 0.1 }); + + // 系统通知(时光胶囊) + if (msg.type === 'system_notification') { + this._playSystemNotification(msg); + return; + } + + this._skipRequested = false; + + // 文字消息(TTS 朗读) + if (msg.type === 'wechat_text' && msg.text) { + await TTS.speak(msg.text); + } + // 语音消息 + else if (msg.audio?.length > 0) { + await this._playVoiceAsync(msg.audio); + } + + if (this._skipRequested) return; + if (this.state !== 'playing') return; + + this._afterPlayed(msg); + } + + _playSystemNotification(msg) { + Snd.playVoice([msg.systemAudio], { + onEnd: () => { + if (this.state !== 'playing') return; + const audio = msg.audioByProfile?.[this.profile.label]; + if (audio) { + if (msg.stateOnPlay) this._applyState(msg.stateOnPlay); + if (msg.profileOnPlay) this.profile.add(msg.profileOnPlay); + setTimeout(() => { + if (this.state !== 'playing') return; + Snd.playVoice([audio], { + onEnd: () => this._proceedToNext(), + }); + }, 800); + } else { + this._proceedToNext(); + } + }, + }); + } + + _afterPlayed(msg) { + if (this.state !== 'playing') return; + + if (msg.isEnding) { + this.triggerFinalEnding(); + return; + } + + if (msg.choices) { + this._enterChoosing(msg.choices); + return; + } + + this._proceedToNext(); + } + + // ══════════════════════════════════════════ + // 选择系统(v2 多轮对话核心) + // ══════════════════════════════════════════ + + _enterChoosing(choices) { + this._currentChoices = choices; + this.state = 'choosing'; + SFX_UI.choiceReady(); + Haptic.confirm(); + Snd.playVoice([`${T}/v2_sys_wait_reply_wav_v1.mp3`]); + this._startReminder(); + } + + async _handleChoice(dir) { + const choices = this._currentChoices; + if (!choices) { + SFX_UI.error(); + Haptic.error(); + return; + } + + const choice = choices[dir]; + if (!choice) { + SFX_UI.error(); + Haptic.error(); + return; + } + + this._clearReminder(); + this._skipRequested = false; + + // 1. 播放方向对应的情感音效 + const sfxMap = { + tap: 'tap', + right: 'choiceWarm', + left: 'choiceCold', + up: 'choiceCurious', + down: 'choiceSilent', + }; + if (sfxMap[dir]) SFX_UI[sfxMap[dir]](); + Haptic.select(); + + // 2. 应用状态和画像 + if (!choice.isSilence) { + this.msgState[this.currentMsg.id] = 'replied'; + this.vars.REPLY_COUNT++; + } + if (choice.state) this._applyState(choice.state); + if (choice.profile) this.profile.add(choice.profile); + + // 3. 林夏回应 + this.state = 'responding'; + + if (choice.isSilence) { + // 沉默:短暂停顿 + await sleep(1500); + } else if (choice.linxia) { + // 打字 → 发送 → 林夏语音 + await this._playTypingSend(); + if (!this._skipRequested) { + await this._playVoiceAsync([choice.linxia]); + } + } + + if (this._skipRequested) { + // 跳过了林夏回应 → 如有 followUp 进入选择,否则跳到下一条 + if (choice.followUp?.choices) { + this._enterChoosing(choice.followUp.choices); + return; + } + this._proceedToNext(); + return; + } + + // 4. NPC 反应 + if (choice.npcReact?.length > 0) { + this.state = 'reacting'; + await sleep(400); + if (!this._skipRequested) { + await this._playVoiceAsync(choice.npcReact); + } + } + + if (this._skipRequested) { + if (choice.followUp?.choices) { + this._enterChoosing(choice.followUp.choices); + return; + } + this._proceedToNext(); + return; + } + + // 5. 如有后续对话 → 再次进入选择 + if (choice.followUp?.choices) { + await sleep(300); + this._enterChoosing(choice.followUp.choices); + return; + } + + // 6. 推进到下一条 + this._proceedToNext(); + } + + _skipChoice() { + this._clearReminder(); + SFX_UI.skip(); + Haptic.confirm(); + this.profile.add({ avoidance: 1 }); + this._proceedToNext(); + } + + // ══════════════════════════════════════════ + // 推进到下一条 + // ══════════════════════════════════════════ + + async _proceedToNext() { + const prev = this.currentMsg; + this.currentMsg = null; + this._currentChoices = null; + this.state = 'idle'; + this._clearReminder(); + + if (this._endingTriggered) return; + + // 特殊事件:阿哲来了(门铃) + if (prev?.id === 11 && this.vars.HE_BACK === true) { + await sleep(1500); + Snd.playVoice([`${SFX}/sfx_door_knock_gentle_v1.mp3`]); + Haptic.ring(); + await sleep(3000); + } + + // 检查结局D:未读过多 + const triggered = MESSAGES.length - this._queue.length; + if (this.vars.UNREAD >= 8 && triggered >= 14) { + this._triggerEnding('D'); + return; + } + + // 短暂停顿后推进 + SFX_UI.next(); + await sleep(DEV ? 200 : 2000); + this._next(); + } + + // ══════════════════════════════════════════ + // 提醒定时器 + // ══════════════════════════════════════════ + + _startReminder() { + this._clearReminder(); + this._reminderTimer = setInterval(() => { + if (this.state === 'notification') { + SFX_UI.notify(); + Haptic.message(); + } else if (this.state === 'choosing') { + SFX_UI.choiceReady(); + Haptic.confirm(); + } else if (this.state === 'ringing') { + Haptic.ring(); + } else { + this._clearReminder(); + } + }, 8000); + } + + _clearReminder() { + if (this._reminderTimer) { + clearInterval(this._reminderTimer); + this._reminderTimer = null; + } + } + + // ══════════════════════════════════════════ + // 状态变量 + // ══════════════════════════════════════════ + + _applyState(changes) { + for (const [k, v] of Object.entries(changes)) { + if (k === 'ZHOUNAN_DEPTH_ADD') { + this.vars.ZHOUNAN_DEPTH += (v || 1); + } else if (v !== null) { + this.vars[k] = v; + } + } + } + + // ══════════════════════════════════════════ + // 手势处理 + // ══════════════════════════════════════════ + + _onTap() { + const s = this.state; + + // 暂停中 → 恢复 + if (s === 'paused') { + this._onResume(); + return; + } + + if (s === 'ringing') { + this._answerCall(this.currentMsg); + } else if (s === 'notification') { + SFX_UI.tap(); + Haptic.confirm(); + this._playMessage(this.currentMsg); + } else if (s === 'choosing') { + this._handleChoice('tap'); + } + } + + _onDoubleTap() { + const s = this.state; + + if (s === 'paused') return; + + if (s === 'ringing') { + this._rejectCall(this.currentMsg); + return; + } + + if (s === 'notification') { + this._clearReminder(); + SFX_UI.skip(); + Haptic.confirm(); + const msg = this.currentMsg; + if (msg?.profileOnSkip) this.profile.add(msg.profileOnSkip); + else this.profile.add({ avoidance: 1 }); + this._proceedToNext(); + return; + } + + if (s === 'playing') { + this._skipRequested = true; + this._interruptVoice(); + SFX_UI.skip(); + Haptic.confirm(); + const msg = this.currentMsg; + if (msg?.isEnding) { + this.triggerFinalEnding(); + } else if (msg?.choices) { + this._enterChoosing(msg.choices); + } else { + this._proceedToNext(); + } + return; + } + + if (s === 'responding' || s === 'reacting') { + this._skipRequested = true; + this._interruptVoice(); + SFX_UI.skip(); + Haptic.confirm(); + return; + } + + if (s === 'choosing') { + this._skipChoice(); + return; + } + } + + _onSwipe(dir) { + const s = this.state; + + if (s === 'paused') return; + + if (s === 'ringing') { + if (dir === 'left') this._rejectCall(this.currentMsg); + else if (dir === 'right') this._answerCall(this.currentMsg); + return; + } + + if (s === 'notification') { + if (dir === 'left') { + this._clearReminder(); + SFX_UI.skip(); + Haptic.confirm(); + this.profile.add({ avoidance: 1 }); + this._proceedToNext(); + } + return; + } + + if (s === 'choosing') { + this._handleChoice(dir); + return; + } + } + + // ── 长按:重播 / 状态广播 ── + _onLongPress() { + const s = this.state; + + if (s === 'paused' || s === 'ending') return; + + Haptic.confirm(); + + // playing/responding/reacting/choosing → 重播当前消息音频 + if ((s === 'playing' || s === 'responding' || s === 'reacting' || s === 'choosing') && this.currentMsg) { + this._interruptVoice(); + if (this.currentMsg.audio?.length > 0) { + this._playVoiceAsync(this.currentMsg.audio); + } else if (this.currentMsg.type === 'wechat_text' && this.currentMsg.text) { + TTS.speak(this.currentMsg.text); + } + return; + } + + // idle/notification → 广播未读数 + TTS.speak(`当前未读${this.vars.UNREAD}条消息`); + } + + // ── 暂停 ── + _onPause() { + const s = this.state; + if (s === 'ending' || s === 'paused') return; + + this._pausedState = s; + this._interruptVoice(); + this._clearReminder(); + Haptic.stop(); + this.state = 'paused'; + Snd.playVoice([`${T}/v2_sys_paused_wav_v1.mp3`]); + } + + // ── 恢复 ── + _onResume() { + Snd.stopVoice(); + const prev = this._pausedState || 'idle'; + this._pausedState = null; + + // 语音无法断点续播,根据暂停前状态决定恢复行为 + if (prev === 'choosing' && this._currentChoices) { + this.state = 'choosing'; + SFX_UI.choiceReady(); + Haptic.confirm(); + this._startReminder(); + } else if (prev === 'notification' || prev === 'ringing') { + this.state = prev; + this._startReminder(); + } else { + // playing/responding/reacting → 无法续播,推进到下一条或回到选择 + if (this._currentChoices) { + this._enterChoosing(this._currentChoices); + } else { + this._proceedToNext(); + } + } + } + + // ── 退出 ── + _onExit() { + if (this.state !== 'paused') return; + + this._endingTriggered = true; + this._interruptVoice(); + // 退出不需要特殊音频,直接返回开始页 + setTimeout(() => { + const startEl = document.getElementById('start'); + if (startEl) { + startEl.style.opacity = '1'; + startEl.style.display = 'flex'; + } + }, 2000); + } + + // ══════════════════════════════════════════ + // 结局系统 + // ══════════════════════════════════════════ + + async triggerFinalEnding() { + if (this._endingTriggered) return; + + const v = this.vars; + + // 结局E(隐藏)— 优先级 1 + if (v.ZHOUNAN_DEPTH >= 2 && v.ZHOUNAN_SHARE && + (this.profile.label === 'engagement' || this.profile.label === 'nostalgia')) { + return this._triggerEnding('E'); + } + + // 结局A:妈妈连接 + 自己录音 — 优先级 2 + if (v.MOM_LINK && v.SELF_RECORD) { + return this._triggerEnding('A'); + } + + // 结局B:拒了阿哲 + 回了周南 — 优先级 3 + if (v.HE_BACK === false && v.ZHOUNAN_DEPTH >= 1) { + return this._triggerEnding('B'); + } + + // 结局C:全部已读但极少回复 — 优先级 4 + const read = Object.values(this.msgState).filter(s => s !== 'unread').length; + if (read >= MESSAGES.length - 2 && v.REPLY_COUNT <= 2) { + return this._triggerEnding('C'); + } + + // 结局D(兜底)— 优先级 5 + this._triggerEnding('D'); + } + + async _triggerEnding(type) { + if (this._endingTriggered) return; + this._endingTriggered = true; + + this.state = 'ending'; + this._clearReminder(); + this._interruptVoice(); + Snd.stopRingtone(); + Snd.stopBGM(3000); + await sleep(2000); + + dbg(`ending: ${type}`); + + const fn = { + A: () => this._endingA(), + B: () => this._endingB(), + C: () => this._endingC(), + D: () => this._endingD(), + E: () => this._endingE(), + }[type]; + if (fn) await fn(); + + // 结局后播报心理支持热线 + await sleep(3000); + await this._playVoiceAsync([`${T}/v2_sys_hotline_wav_v1.mp3`]); + } + + async _endingA() { + Snd.startAmbience(`${AMB}/amb_kitchen_morning_v1.mp3`, { vol: 0.3 }); + await sleep(2000); + Snd.playVoice([`${SFX}/sfx_kettle_whistle_v1.mp3`]); + await sleep(4000); + SFX_UI.ending(); + this._showCaption('明天再说。'); + await this._playVoiceAsync([`${T}/v2_ending_a_linxia_wav_v1.mp3`]); + } + + async _endingB() { + await sleep(2000); + SFX_UI.ending(); + await sleep(1000); + this._showCaption('寄出去了。'); + await this._playVoiceAsync([`${T}/v2_ending_b_linxia_wav_v1.mp3`]); + } + + async _endingC() { + await sleep(3000); + SFX_UI.ending(); + await sleep(1000); + this._showCaption('今晚就这样。'); + await this._playVoiceAsync([`${T}/v2_ending_c_linxia_wav_v1.mp3`]); + } + + async _endingD() { + Haptic.system(); + await sleep(2000); + Haptic.ring(); + await sleep(4000); + Snd.startAmbience(`${AMB}/amb_dawn_birds_v1.mp3`, { vol: 0.4 }); + await sleep(4000); + this._showCaption('早上好。'); + await this._playVoiceAsync([`${T}/v2_ending_d_linxia_wav_v1.mp3`]); + } + + async _endingE() { + Haptic.message(); + SFX_UI.notify(); + await sleep(1500); + // 周南秒回:"那我下次出差来北京,请你吃饭好不好。" + await this._playVoiceAsync([`${T}/v2_ending_e_zhounan_wav_v1.mp3`]); + await sleep(2000); + SFX_UI.ending(); + await sleep(1000); + this._showCaption('好。'); + await this._playVoiceAsync([`${T}/v2_ending_e_linxia_wav_v1.mp3`]); + } + + _showCaption(text) { + const el = document.getElementById('caption'); + el.textContent = text; + el.style.display = 'flex'; + } +} diff --git a/game1/js/gestures.js b/game1/js/gestures.js new file mode 100644 index 0000000..8185a57 --- /dev/null +++ b/game1/js/gestures.js @@ -0,0 +1,262 @@ +// gestures.js — 触控手势检测器 +// +// 支持 9 种手势: +// 单击 · 双击 · 长按(1s) · 左滑 · 右滑 · 上滑 · 下滑 +// 两指长按(1s) · 三指点击 + +class GestureDetector { + constructor(el) { + this._el = el; + this._handlers = {}; + + this._startX = 0; + this._startY = 0; + this._startTime = 0; + this._tapTimer = null; + this._tapCount = 0; + + // 长按检测 + this._longPressTimer = null; + this._longPressTriggered = false; + + // 多指检测 + this._maxTouches = 0; // 本次触摸中同时出现的最大手指数 + this._multiTouchLPTimer = null; // 两指长按计时器 + this._multiTouchHandled = false; + + this._bindTouch(); + this._bindMouse(); + this._bindKeyboard(); + } + + on(evt, fn) { this._handlers[evt] = fn; return this; } + + _emit(evt) { + dbg(evt); + const fn = this._handlers[evt]; + if (fn) fn(); + } + + // ── 触摸事件 ── + _bindTouch() { + const el = this._el; + + el.addEventListener('touchstart', e => { + e.preventDefault(); + const count = e.touches.length; + + // 记录本次触摸出现过的最大手指数 + if (count > this._maxTouches) this._maxTouches = count; + + if (count === 1) { + // 单指:记录起点 + 启动长按计时 + const t = e.touches[0]; + this._startX = t.clientX; + this._startY = t.clientY; + this._startTime = Date.now(); + this._longPressTriggered = false; + + this._longPressTimer = setTimeout(() => { + this._longPressTriggered = true; + this._longPressTimer = null; + this._emit('longpress'); + }, 1000); + + } else if (count === 2) { + // 两指:取消单指长按,启动两指长按计时 + this._cancelLongPress(); + this._multiTouchLPTimer = setTimeout(() => { + this._multiTouchHandled = true; + this._multiTouchLPTimer = null; + this._emit('twofinger_longpress'); + }, 1000); + + } else if (count >= 3) { + // 三指+:取消所有计时 + this._cancelLongPress(); + this._cancelMultiTouchLP(); + } + }, { passive: false }); + + el.addEventListener('touchmove', e => { + e.preventDefault(); + // 移动超 15px 取消长按 + if (this._longPressTimer && e.touches.length === 1) { + const t = e.touches[0]; + const dx = t.clientX - this._startX; + const dy = t.clientY - this._startY; + if (Math.sqrt(dx * dx + dy * dy) > 15) { + this._cancelLongPress(); + } + } + // 两指移动也取消两指长按 + if (this._multiTouchLPTimer) { + this._cancelMultiTouchLP(); + } + }, { passive: false }); + + el.addEventListener('touchend', e => { + e.preventDefault(); + + // 还有手指在屏幕上,等全部抬起再处理 + if (e.touches.length > 0) return; + + // 全部手指抬起 — 根据 maxTouches 判定手势类型 + const max = this._maxTouches; + + // 清理计时器 + this._cancelLongPress(); + this._cancelMultiTouchLP(); + + // 已在计时器中处理过(长按 / 两指长按) + if (this._longPressTriggered || this._multiTouchHandled) { + this._resetMultiTouch(); + return; + } + + // 三指点击 + if (max >= 3) { + this._resetMultiTouch(); + this._emit('threefinger_tap'); + return; + } + + // 两指快速触摸(< 1s)→ 忽略 + if (max === 2) { + this._resetMultiTouch(); + return; + } + + // 单指:正常处理(滑动 / 点击) + this._resetMultiTouch(); + const t = e.changedTouches[0]; + this._process(t.clientX, t.clientY); + }, { passive: false }); + + el.addEventListener('touchcancel', () => { + this._cancelLongPress(); + this._cancelMultiTouchLP(); + this._resetMultiTouch(); + this._reset(); + }, { passive: false }); + } + + // ── 鼠标事件(桌面调试)── + _bindMouse() { + this._el.addEventListener('mousedown', e => { + this._startX = e.clientX; + this._startY = e.clientY; + this._startTime = Date.now(); + this._longPressTriggered = false; + + this._longPressTimer = setTimeout(() => { + this._longPressTriggered = true; + this._longPressTimer = null; + this._emit('longpress'); + }, 1000); + }); + this._el.addEventListener('mouseup', e => { + this._cancelLongPress(); + if (this._longPressTriggered) { + this._longPressTriggered = false; + return; + } + this._process(e.clientX, e.clientY); + }); + this._el.addEventListener('mousemove', e => { + if (this._longPressTimer) { + const dx = e.clientX - this._startX; + const dy = e.clientY - this._startY; + if (Math.sqrt(dx * dx + dy * dy) > 15) { + this._cancelLongPress(); + } + } + }); + } + + // ── 键盘事件(桌面调试)── + _bindKeyboard() { + document.addEventListener('keydown', e => { + switch (e.code) { + case 'Space': e.preventDefault(); this._emit('singletap'); break; + case 'Enter': e.preventDefault(); this._emit('doubletap'); break; + case 'ArrowLeft': e.preventDefault(); this._emit('swipe_left'); break; + case 'ArrowRight': e.preventDefault(); this._emit('swipe_right'); break; + case 'ArrowUp': e.preventDefault(); this._emit('swipe_up'); break; + case 'ArrowDown': e.preventDefault(); this._emit('swipe_down'); break; + case 'KeyL': e.preventDefault(); this._emit('longpress'); break; + case 'KeyP': e.preventDefault(); this._emit('twofinger_longpress'); break; + case 'KeyQ': e.preventDefault(); this._emit('threefinger_tap'); break; + } + }); + } + + // ── 手势判定(单指) ── + _process(endX, endY) { + const dx = endX - this._startX; + const dy = endY - this._startY; + const dist = Math.sqrt(dx * dx + dy * dy); + const dt = Date.now() - this._startTime; + + // 滑动:距离 > 35px + if (dist > 35) { + const angle = Math.abs(Math.atan2(dy, dx) * 180 / Math.PI); + let dir = null; + + if (angle < 45) dir = 'right'; + else if (angle > 135) dir = 'left'; + else if (dy < 0 && Math.abs(dy) > Math.abs(dx)) dir = 'up'; + else if (dy > 0 && Math.abs(dy) > Math.abs(dx)) dir = 'down'; + + if (dir) { + this._tapCount = 0; + clearTimeout(this._tapTimer); + this._emit(`swipe_${dir}`); + return; + } + } + + // 点击:距离 < 20px,时间 < 500ms + if (dist < 20 && dt < 500) { + this._tapCount++; + if (this._tapCount === 1) { + this._tapTimer = setTimeout(() => { + this._tapCount = 0; + this._emit('singletap'); + }, 250); + } else if (this._tapCount >= 2) { + clearTimeout(this._tapTimer); + this._tapCount = 0; + this._emit('doubletap'); + } + } + } + + // ── 工具方法 ── + + _cancelLongPress() { + if (this._longPressTimer) { + clearTimeout(this._longPressTimer); + this._longPressTimer = null; + } + } + + _cancelMultiTouchLP() { + if (this._multiTouchLPTimer) { + clearTimeout(this._multiTouchLPTimer); + this._multiTouchLPTimer = null; + } + } + + _resetMultiTouch() { + this._maxTouches = 0; + this._multiTouchHandled = false; + } + + _reset() { + clearTimeout(this._tapTimer); + this._tapCount = 0; + this._longPressTriggered = false; + this._resetMultiTouch(); + } +} diff --git a/game1/js/haptics.js b/game1/js/haptics.js new file mode 100644 index 0000000..02bbbce --- /dev/null +++ b/game1/js/haptics.js @@ -0,0 +1,35 @@ +// haptics.js — 震动反馈(Android Chrome 支持,iOS 降级为无震动) + +const Haptic = { + _ok: typeof navigator !== 'undefined' && !!navigator.vibrate, + + _v(pattern) { + if (this._ok) navigator.vibrate(pattern); + }, + + // 来电震动(长震 + 停顿,循环由来电循环调用) + ring() { this._v([400, 200, 400]); }, + + // 微信消息(两短震) + message() { this._v([80, 60, 80]); }, + + // 确认操作 + confirm() { this._v(60); }, + + // 拒绝 / 挂断 + reject() { this._v([100, 50, 100, 50, 100]); }, + + // 进入细回复模式 + detailMode() { this._v([30, 30, 60]); }, + + // 选项选中 + select() { this._v(80); }, + + // 系统通知 + system() { this._v([200, 100, 100, 100, 200]); }, + + // 错误 / 无效手势 + error() { this._v([50, 30, 50]); }, + + stop() { if (this._ok) navigator.vibrate(0); }, +}; diff --git a/game1/js/main.js b/game1/js/main.js new file mode 100644 index 0000000..fbd60bc --- /dev/null +++ b/game1/js/main.js @@ -0,0 +1,55 @@ +// main.js — 游戏入口 + +let engine = null; +let gestures = null; + +async function main() { + TTS.init(); + + // 初始化音频(必须在用户手势后) + await Snd.init(); + + // 请求屏幕常亮 + try { + if ('wakeLock' in navigator) { + window._wakeLock = await navigator.wakeLock.request('screen'); + } + } catch (_) {} + + // 绑定手势 + const gameEl = document.getElementById('game'); + gestures = new GestureDetector(gameEl); + + // 创建并启动引擎 + engine = new GameEngine(); + engine.init(gestures); + await engine.start(); + + if (DEV) { + document.getElementById('dbg').style.display = 'block'; + document.title = '林夏 [DEV]'; + } +} + +// 触摸启动(手机) +document.getElementById('start').addEventListener('touchend', async function onStart(e) { + e.preventDefault(); + this.removeEventListener('touchend', onStart); + this.style.transition = 'opacity 0.8s'; + this.style.opacity = '0'; + setTimeout(() => { this.style.display = 'none'; }, 800); + await main(); +}, { once: true }); + +// 鼠标点击(电脑调试) +document.getElementById('start').addEventListener('click', async function onClick() { + this.removeEventListener('click', onClick); + this.style.transition = 'opacity 0.8s'; + this.style.opacity = '0'; + setTimeout(() => { this.style.display = 'none'; }, 800); + await main(); +}, { once: true }); + +// 防止页面滚动/缩放 +document.addEventListener('touchmove', e => e.preventDefault(), { passive: false }); +document.addEventListener('gesturestart', e => e.preventDefault()); diff --git a/game1/js/profile.js b/game1/js/profile.js new file mode 100644 index 0000000..c5d6024 --- /dev/null +++ b/game1/js/profile.js @@ -0,0 +1,39 @@ +// profile.js — 行为画像追踪器(avoidance / engagement / nostalgia) + +class ProfileTracker { + constructor() { + this.scores = { avoidance: 0, engagement: 0, nostalgia: 0 }; + } + + add(effects) { + if (!effects) return; + for (const k of ['avoidance', 'engagement', 'nostalgia']) { + if (effects[k]) this.scores[k] += effects[k]; + } + } + + // 漏接电话 + onMissedCall() { this.add({ avoidance: 2 }); } + // 单点回"嗯" + onSimpleReply() { this.add({ avoidance: 1 }); } + // 双指上滑已读不回 + onReadNoReply() { this.add({ avoidance: 2 }); } + // 进入细回复 + onDetailReply() { this.add({ engagement: 2 }); } + // 细回复选"主动追问"(engagement 方向) + onEngage() { this.add({ engagement: 2 }); } + // 细回复选"分享自己" + onShare() { this.add({ engagement: 1, nostalgia: 1 }); } + // 反复重听同一条 + onReplay() { this.add({ nostalgia: 2 }); } + // 听完长语音未回应 + onListenNoReact(){ this.add({ avoidance: 1, nostalgia: 1 }); } + + // 获取最终画像标签 + get label() { + const s = this.scores; + if (s.engagement >= s.avoidance && s.engagement >= s.nostalgia) return 'engagement'; + if (s.nostalgia >= s.avoidance) return 'nostalgia'; + return 'avoidance'; + } +} diff --git a/game1/js/story.js b/game1/js/story.js new file mode 100644 index 0000000..de63bc0 --- /dev/null +++ b/game1/js/story.js @@ -0,0 +1,674 @@ +// story.js — 消息数据 v2(CosyVoice2 语音 + 多轮对话) +// +// 选择方向的情感含义(全局一致): +// 单击(tap) → 简单回应 +// 双击 → 不回复 / 跳过 +// 右滑(right) → 温暖 / 接受 / 开放 +// 左滑(left) → 冷淡 / 拒绝 / 疏远 +// 上滑(up) → 好奇 / 主动 / 追问 +// 下滑(down) → 沉默 / 退缩 +// +// 每个 choice 结构: +// linxia: 林夏回应的音频路径(null/缺省 = 沉默) +// npcReact: NPC反应音频数组(缺省 = 无反应) +// isSilence: 沉默选项标记 +// state: 剧情状态变更 +// profile: 画像分数变更 +// followUp: 可选的下一轮对话 { choices: { ... } } + +const A = 'mp3'; +const T = `${A}/tts`; // CosyVoice2 生成的所有语音 +const MUS = `${A}/music`; +const SFX = `${A}/sfx`; +const AMB = `${A}/ambience`; + +// ── 快捷函数 ── +const npc = f => `${T}/${f}`; // NPC Round 1 台词 +const lx = f => `${T}/${f}`; // 林夏回应 +const rx = f => `${T}/${f}`; // NPC 反应 + +const MESSAGES = [ + + // ══════════════════════════════════════════ + // 01 · 妈妈 · 电话 + // ══════════════════════════════════════════ + { + id: 1, type: 'call', + sender: 'mom', senderName: '妈妈', + ringtone: `${MUS}/lv11_ring_mom_v1.mp3`, + audio: [npc('lv11_2103_mom_call_01_wav_v1.mp3')], + autoReply: lx('v2_msg01_linxia_auto_wav_v1.mp3'), + stateOnAnswer: { MOM_LINK: true }, + profileOnMiss: { avoidance: 2 }, + profileOnAnswer: { engagement: 1 }, + }, + + // ══════════════════════════════════════════ + // 02 · 小美 · 语音 ×3(教学关) + // ══════════════════════════════════════════ + { + id: 2, type: 'wechat_voice', + sender: 'xiaomei', senderName: '小美', + audio: [ + npc('lv11_2115_xiaomei_voice_01_wav_v1.mp3'), + npc('lv11_2115_xiaomei_voice_02_wav_v1.mp3'), + npc('lv11_2115_xiaomei_voice_03_wav_v1.mp3'), + ], + choices: { + right: { + linxia: lx('v2_msg02_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg02_react_warm_wav_v1.mp3')], + profile: { engagement: 2 }, + }, + left: { + linxia: lx('v2_msg02_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg02_react_cold_wav_v1.mp3')], + profile: { avoidance: 1 }, + }, + up: { + linxia: lx('v2_msg02_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg02_react_curious_wav_v1.mp3')], + profile: { engagement: 1 }, + followUp: { + choices: { + right: { + linxia: lx('v2_msg02_r3_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg02_r3_react_wav_v1.mp3')], + profile: { nostalgia: 1 }, + }, + }, + }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg02_react_silent_wav_v1.mp3')], + profile: { avoidance: 2 }, + }, + tap: { + linxia: lx('v2_msg02_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg02_react_tap_wav_v1.mp3')], + }, + }, + }, + + // ══════════════════════════════════════════ + // 03 · 外卖小哥 · 电话 + // ══════════════════════════════════════════ + { + id: 3, type: 'call', + sender: 'delivery', senderName: '外卖小哥', + ringtone: `${MUS}/lv11_ring_delivery_v1.mp3`, + audio: [npc('lv11_2120_delivery_call_01_wav_v1.mp3')], + autoReply: lx('v2_msg03_linxia_auto_wav_v1.mp3'), + profileOnMiss: { avoidance: 1 }, + profileOnAnswer: { engagement: 1 }, + }, + + // ══════════════════════════════════════════ + // 04 · 阿哲 · 语音(前男友要东西) + // ══════════════════════════════════════════ + { + id: 4, type: 'wechat_voice', + sender: 'azhe', senderName: '阿哲', + audio: [npc('lv11_2130_azhe_voice_01_wav_v1.mp3')], + choices: { + right: { + linxia: lx('v2_msg04_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg04_react_warm_wav_v1.mp3')], + profile: { engagement: 2 }, + followUp: { + // 阿哲问"你呢?"后 + choices: { + right: { + linxia: lx('v2_msg04_r3w_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg04_r3w_react_warm_wav_v1.mp3')], + }, + left: { + linxia: lx('v2_msg04_r3w_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg04_r3w_react_cold_wav_v1.mp3')], + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg04_r3w_react_silent_wav_v1.mp3')], + }, + }, + }, + }, + left: { + linxia: lx('v2_msg04_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg04_react_cold_wav_v1.mp3')], + state: { HE_BACK: false }, + profile: { avoidance: 1 }, + }, + up: { + linxia: lx('v2_msg04_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg04_react_curious_wav_v1.mp3')], + profile: { engagement: 2 }, + followUp: { + // 阿哲说"不太方便"后 + choices: { + up: { + linxia: lx('v2_msg04_r3c_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg04_r3c_react_curious_wav_v1.mp3')], + state: { HE_BACK: false }, + }, + right: { + linxia: lx('v2_msg04_r3c_linxia_warm_wav_v1.mp3'), + }, + }, + }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg04_react_silent_wav_v1.mp3')], + state: { HE_BACK: null }, + profile: { avoidance: 2 }, + }, + tap: { + linxia: lx('v2_msg04_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg04_react_tap_wav_v1.mp3')], + state: { HE_BACK: false }, + profile: { engagement: 1 }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 05 · HR王姐 · 语音 + // ══════════════════════════════════════════ + { + id: 5, type: 'wechat_voice', + sender: 'hr', senderName: 'HR王姐', + audio: [npc('lv11_2145_hr_voice_01_wav_v1.mp3')], + choices: { + right: { + linxia: lx('v2_msg05_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg05_react_warm_wav_v1.mp3')], + profile: { engagement: 1 }, + }, + left: { + linxia: lx('v2_msg05_linxia_cold_wav_v1.mp3'), + }, + up: { + linxia: lx('v2_msg05_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg05_react_curious_wav_v1.mp3')], + profile: { engagement: 2 }, + }, + down: { + isSilence: true, + profile: { avoidance: 1 }, + }, + tap: { + linxia: lx('v2_msg05_linxia_tap_wav_v1.mp3'), + }, + }, + }, + + // ══════════════════════════════════════════ + // 06 · 安安 · 语音(酒吧邀约) + // ══════════════════════════════════════════ + { + id: 6, type: 'wechat_voice', + sender: 'anan', senderName: '安安', + audio: [npc('lv11_2200_anan_voice_01_wav_v1.mp3')], + choices: { + right: { + linxia: lx('v2_msg06_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg06_react_warm_wav_v1.mp3')], + profile: { engagement: 2 }, + }, + left: { + linxia: lx('v2_msg06_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg06_react_cold_wav_v1.mp3')], + }, + up: { + linxia: lx('v2_msg06_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg06_react_curious_wav_v1.mp3')], + profile: { engagement: 1 }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg06_react_silent_wav_v1.mp3')], + profile: { avoidance: 1 }, + }, + tap: { + linxia: lx('v2_msg06_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg06_react_tap_wav_v1.mp3')], + }, + }, + }, + + // ══════════════════════════════════════════ + // 07 · 寝室群 · 5条语音 + // ══════════════════════════════════════════ + { + id: 7, type: 'wechat_voice', + sender: 'dorm', senderName: '寝室群', + audio: [ + npc('lv11_2215_dorm_a_voice_01_wav_v1.mp3'), + npc('lv11_2215_dorm_b_voice_01_wav_v1.mp3'), + npc('lv11_2215_dorm_c_voice_01_wav_v1.mp3'), + npc('lv11_2215_dorm_a_voice_02_wav_v1.mp3'), + npc('lv11_2215_dorm_b_voice_02_wav_v1.mp3'), + ], + choices: { + right: { + linxia: lx('v2_msg07_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg07_react_warm_wav_v1.mp3')], + state: { GROUP_REPLY: true }, + profile: { engagement: 2 }, + followUp: { + // 室友A问"你最近怎么样"后 + choices: { + right: { + linxia: lx('v2_msg07_r3_linxia_warm_wav_v1.mp3'), + profile: { engagement: 1 }, + }, + left: { + linxia: lx('v2_msg07_r3_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg07_r3_react_cold_wav_v1.mp3')], + }, + }, + }, + }, + left: { + linxia: lx('v2_msg07_linxia_cold_wav_v1.mp3'), + profile: { avoidance: 1 }, + }, + up: { + linxia: lx('v2_msg07_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg07_react_curious_wav_v1.mp3')], + state: { GROUP_REPLY: true }, + profile: { engagement: 2 }, + }, + down: { + isSilence: true, + profile: { avoidance: 2 }, + }, + tap: { + linxia: lx('v2_linxia_generic_hmm_wav_v1.mp3'), + npcReact: [rx('v2_msg07_react_tap_wav_v1.mp3')], + state: { GROUP_REPLY: true }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 08 · 未知号码 · 电话(悬疑钩子) + // ══════════════════════════════════════════ + { + id: 8, type: 'call', + sender: 'unknown', senderName: '未知号码', + ringtone: `${MUS}/lv11_ring_unknown_v1.mp3`, + audio: [`${SFX}/sfx_breathing_unknown_v1.mp3`], + autoHangup: true, + sfxAfter: `${SFX}/sfx_heartbeat_fast_v1.mp3`, + profileOnMiss: { avoidance: 1 }, + profileOnAnswer: { nostalgia: 1 }, + }, + + // ══════════════════════════════════════════ + // 09 · 小美(醉)· 4段语音 + // ══════════════════════════════════════════ + { + id: 9, type: 'wechat_voice', + sender: 'xiaomei', senderName: '小美', + audio: [ + npc('lv11_2245_xiaomei_voice_01_seg1_wav_v1.mp3'), + npc('lv11_2245_xiaomei_voice_01_seg2_wav_v1.mp3'), + npc('lv11_2245_xiaomei_voice_01_seg3_wav_v1.mp3'), + npc('lv11_2245_xiaomei_voice_01_seg4_wav_v1.mp3'), + ], + bgm: `${MUS}/lv11_bgm_m2_suspense_v1.mp3`, + choices: { + right: { + linxia: lx('v2_msg09_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg09_react_warm_wav_v1.mp3')], + profile: { engagement: 2 }, + }, + left: { + linxia: lx('v2_msg09_linxia_cold_wav_v1.mp3'), + profile: { avoidance: 1 }, + }, + up: { + linxia: lx('v2_msg09_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg09_react_curious_wav_v1.mp3')], + profile: { engagement: 2 }, + followUp: { + // 小美说"怕你恨我"后 + choices: { + right: { + linxia: lx('v2_msg09_r3_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg09_r3_react_warm_wav_v1.mp3')], + }, + left: { + linxia: lx('v2_msg09_r3_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg09_r3_react_cold_wav_v1.mp3')], + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg09_r3_react_silent_q_wav_v1.mp3')], + }, + }, + }, + }, + down: { + isSilence: true, + profile: { avoidance: 2, nostalgia: 1 }, + }, + tap: { + linxia: lx('v2_msg09_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg09_react_tap_wav_v1.mp3')], + profile: { nostalgia: 1 }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 10 · 妈妈 · 文字消息(多层嵌套对话) + // ══════════════════════════════════════════ + { + id: 10, type: 'wechat_text', + sender: 'mom', senderName: '妈妈', + text: '睡了吗?', + choices: { + right: { + linxia: lx('v2_msg10_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg10_react_warm_wav_v1.mp3')], + state: { MOM_LINK: true }, + profile: { engagement: 2 }, + followUp: { + // 妈妈问"今天怎么样"后 + choices: { + right: { + linxia: lx('v2_msg10_rw_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg10_rw_react_warm_wav_v1.mp3')], + }, + up: { + linxia: lx('v2_msg10_rw_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg10_rw_react_curious_wav_v1.mp3')], + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg10_rw_react_silent_wav_v1.mp3')], + profile: { avoidance: 1 }, + }, + }, + }, + }, + left: { + linxia: lx('v2_msg10_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg10_react_cold_wav_v1.mp3')], + state: { MOM_LINK: true }, + profile: { avoidance: 1 }, + }, + up: { + linxia: lx('v2_msg10_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg10_call_mom_wav_v1.mp3')], + state: { MOM_LINK: true }, + profile: { engagement: 3 }, + followUp: { + // 妈妈打来电话说"怎么了夏夏?"后 + choices: { + right: { + linxia: lx('v2_msg10_call_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg10_call_react_warm_wav_v1.mp3')], + }, + up: { + linxia: lx('v2_msg10_call_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg10_call_react_curious_wav_v1.mp3')], + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg10_call_react_down_wav_v1.mp3')], + profile: { avoidance: 1 }, + }, + }, + }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg10_react_silent_wav_v1.mp3')], + profile: { avoidance: 2 }, + }, + tap: { + linxia: lx('v2_msg10_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg10_react_tap_wav_v1.mp3')], + state: { MOM_LINK: true }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 11 · 阿哲 · 电话(关键分支:来不来) + // ══════════════════════════════════════════ + { + id: 11, type: 'call', + sender: 'azhe', senderName: '阿哲', + ringtone: `${MUS}/lv11_ring_azhe_v1.mp3`, + audio: [npc('lv11_2315_azhe_call_01_wav_v1.mp3')], + profileOnMiss: { avoidance: 2 }, + profileOnAnswer: { engagement: 1 }, + choices: { + right: { + linxia: lx('v2_msg11_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_warm_wav_v1.mp3')], + state: { HE_BACK: true }, + }, + left: { + linxia: lx('v2_msg11_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_cold_wav_v1.mp3')], + state: { HE_BACK: false }, + }, + up: { + linxia: lx('v2_msg11_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_curious_wav_v1.mp3')], + followUp: { + choices: { + right: { + linxia: lx('v2_msg11_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_warm_wav_v1.mp3')], + state: { HE_BACK: true }, + }, + left: { + linxia: lx('v2_msg11_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_cold_wav_v1.mp3')], + state: { HE_BACK: false }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg11_r3_react_silent_wav_v1.mp3')], + state: { HE_BACK: false }, + profile: { avoidance: 1 }, + }, + }, + }, + }, + down: { + isSilence: true, + state: { HE_BACK: false }, + }, + tap: { + linxia: lx('v2_msg11_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg11_react_tap_wav_v1.mp3')], + state: { HE_BACK: false }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 12 · 周南 · 语音(老同学) + // ══════════════════════════════════════════ + { + id: 12, type: 'wechat_voice', + sender: 'zhounan', senderName: '周南', + audio: [npc('lv11_2330_zhounan_voice_01_wav_v1.mp3')], + choices: { + right: { + linxia: lx('v2_msg12_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg12_react_warm_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH: 1 }, + profile: { engagement: 2, nostalgia: 1 }, + }, + left: { + linxia: lx('v2_msg12_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg12_react_cold_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH: 1 }, + profile: { nostalgia: 1 }, + }, + up: { + linxia: lx('v2_msg12_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg12_react_curious_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH: 1 }, + profile: { nostalgia: 2 }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg12_react_silent_wav_v1.mp3')], + profile: { nostalgia: 1 }, + }, + tap: { + linxia: lx('v2_msg12_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg12_react_tap_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH: 1 }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 13 · 周南 · 4条长语音(他的十年) + // ══════════════════════════════════════════ + { + id: 13, type: 'wechat_voice', + sender: 'zhounan', senderName: '周南', + audio: [ + npc('lv11_2345_zhounan_voice_01_wav_v1.mp3'), + npc('lv11_2345_zhounan_voice_02_wav_v1.mp3'), + npc('lv11_2345_zhounan_voice_03_wav_v1.mp3'), + npc('lv11_2345_zhounan_voice_04_wav_v1.mp3'), + ], + bgm: `${MUS}/lv11_bgm_m3_zhounan_v1.mp3`, + choices: { + right: { + linxia: lx('v2_msg13_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg13_react_warm_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH_ADD: 1 }, + profile: { engagement: 2 }, + followUp: { + // 周南问"你在北京过得好吗"后 + choices: { + right: { + linxia: lx('v2_msg13_r3_linxia_warm_wav_v1.mp3'), + npcReact: [rx('v2_msg13_r3_react_warm_wav_v1.mp3')], + state: { ZHOUNAN_SHARE: true }, + }, + left: { + linxia: lx('v2_msg13_r3_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg13_r3_react_cold_wav_v1.mp3')], + }, + up: { + linxia: lx('v2_msg13_r3_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg13_r3_react_curious_wav_v1.mp3')], + }, + }, + }, + }, + left: { + linxia: lx('v2_msg13_linxia_cold_wav_v1.mp3'), + npcReact: [rx('v2_msg13_react_cold_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH_ADD: 1 }, + profile: { nostalgia: 1 }, + }, + up: { + linxia: lx('v2_msg13_linxia_curious_wav_v1.mp3'), + npcReact: [rx('v2_msg13_react_curious_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH_ADD: 1, ZHOUNAN_SHARE: true }, + profile: { nostalgia: 2, engagement: 1 }, + }, + down: { + isSilence: true, + npcReact: [rx('v2_msg13_react_silent_wav_v1.mp3')], + profile: { avoidance: 1 }, + }, + tap: { + linxia: lx('v2_msg13_linxia_tap_wav_v1.mp3'), + npcReact: [rx('v2_msg13_react_tap_wav_v1.mp3')], + state: { ZHOUNAN_DEPTH_ADD: 1 }, + }, + }, + }, + + // ══════════════════════════════════════════ + // 14 · 妈妈 · 第二次电话 + // ══════════════════════════════════════════ + { + id: 14, type: 'call', + sender: 'mom', senderName: '妈妈', + ringtone: `${MUS}/lv11_ring_mom_v1.mp3`, + audio: [npc('lv11_0015_mom_call_01_wav_v1.mp3')], + autoReply: lx('v2_msg14_linxia_auto_wav_v1.mp3'), + autoReact: { + condition: 'MOM_LINK', + true: rx('v2_msg14_react_linked_wav_v1.mp3'), + false: rx('v2_msg14_react_unlinked_wav_v1.mp3'), + }, + autoReactPreamble: rx('v2_msg14_mom_ask_wav_v1.mp3'), + stateOnAnswer: { MOM_LINK: true }, + profileOnMiss: { avoidance: 2 }, + profileOnAnswer: { engagement: 2 }, + }, + + // ══════════════════════════════════════════ + // 15 · 时光胶囊 · 系统通知 + // ══════════════════════════════════════════ + { + id: 15, type: 'system_notification', + sender: 'self', senderName: '时光胶囊', + systemAudio: npc('lv11_sys_memo_01_wav_v1.mp3'), + audioByProfile: { + avoidance: npc('lv11_0030_self3y_voice_02_wav_v1.mp3'), + engagement: npc('lv11_0030_self3y_voice_01_wav_v1.mp3'), + nostalgia: npc('lv11_0030_self3y_voice_03_wav_v1.mp3'), + }, + stateOnPlay: { SELF_RECORD: true }, + profileOnPlay: { nostalgia: 2 }, + profileOnSkip: { avoidance: 2 }, + }, + + // ══════════════════════════════════════════ + // 16 · 妈妈 · 长语音 ×8(结局前奏) + // ══════════════════════════════════════════ + { + id: 16, type: 'wechat_voice', + sender: 'mom', senderName: '妈妈', + audio: [ + npc('lv11_0200_mom_voice_01_seg1_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg2_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg3_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg4_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg5_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg6_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg7_wav_v1.mp3'), + npc('lv11_0200_mom_voice_01_seg8_wav_v1.mp3'), + ], + bgm: `${MUS}/lv11_bgm_m4_ending_v1.mp3`, + isEnding: true, + requiresMomLink: true, + }, +]; + +// 角色信息 +const SENDERS = { + mom: { name: '妈妈' }, + azhe: { name: '阿哲' }, + xiaomei: { name: '小美' }, + delivery: { name: '外卖小哥' }, + hr: { name: 'HR王姐' }, + anan: { name: '安安' }, + dorm: { name: '寝室群' }, + unknown: { name: '未知号码' }, + zhounan: { name: '周南' }, + self: { name: '时光胶囊' }, +}; + +const AMBIENCE_DEFAULT = `${AMB}/amb_apartment_night_01_v1.mp3`; diff --git a/game1/js/utils.js b/game1/js/utils.js new file mode 100644 index 0000000..29a1f93 --- /dev/null +++ b/game1/js/utils.js @@ -0,0 +1,38 @@ +// utils.js — 工具函数 + +const DEV = new URLSearchParams(location.search).has('dev'); + +const sleep = ms => new Promise(r => setTimeout(r, ms)); + +function dbg(msg) { + const el = document.getElementById('dbg'); + if (el && el.style.display !== 'none') el.textContent = msg; +} + +// TTS — 仅用于朗读文字消息内容,不用于任何 UI 反馈 +const TTS = { + _voices: [], + init() { + if (!window.speechSynthesis) return; + const load = () => { this._voices = speechSynthesis.getVoices(); }; + load(); + speechSynthesis.onvoiceschanged = load; + }, + _pick() { + return this._voices.find(v => v.lang.startsWith('zh') || v.name.includes('Chinese')) + || this._voices[0] || null; + }, + speak(text, { rate = 0.85, volume = 0.8 } = {}) { + return new Promise(resolve => { + if (!window.speechSynthesis) { resolve(); return; } + speechSynthesis.cancel(); + const u = new SpeechSynthesisUtterance(text); + u.lang = 'zh-CN'; u.rate = rate; u.volume = volume; + const v = this._pick(); + if (v) u.voice = v; + u.onend = resolve; u.onerror = resolve; + speechSynthesis.speak(u); + }); + }, + stop() { if (window.speechSynthesis) speechSynthesis.cancel(); }, +}; diff --git a/game1/manifest.json b/game1/manifest.json new file mode 100644 index 0000000..af6abcf --- /dev/null +++ b/game1/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "林夏", + "short_name": "林夏", + "description": "一款全黑屏的情感叙事游戏。今晚16条消息,你接谁不接谁,决定明天的自己。", + "start_url": "/game/", + "display": "fullscreen", + "orientation": "portrait", + "background_color": "#000000", + "theme_color": "#000000", + "icons": [ + { "src": "icon.png", "sizes": "192x192", "type": "image/png" } + ] +} diff --git a/game1/mp3/ambience/amb_apartment_night_01_v1.mp3 b/game1/mp3/ambience/amb_apartment_night_01_v1.mp3 new file mode 100644 index 0000000..a9f24a6 Binary files /dev/null and b/game1/mp3/ambience/amb_apartment_night_01_v1.mp3 differ diff --git a/game1/mp3/ambience/amb_apartment_night_02_v1.mp3 b/game1/mp3/ambience/amb_apartment_night_02_v1.mp3 new file mode 100644 index 0000000..53cbc0c Binary files /dev/null and b/game1/mp3/ambience/amb_apartment_night_02_v1.mp3 differ diff --git a/game1/mp3/ambience/amb_bar_loud_01_v1.mp3 b/game1/mp3/ambience/amb_bar_loud_01_v1.mp3 new file mode 100644 index 0000000..91dc7fa Binary files /dev/null and b/game1/mp3/ambience/amb_bar_loud_01_v1.mp3 differ diff --git a/game1/mp3/ambience/amb_dawn_birds_v1.mp3 b/game1/mp3/ambience/amb_dawn_birds_v1.mp3 new file mode 100644 index 0000000..a128b9a Binary files /dev/null and b/game1/mp3/ambience/amb_dawn_birds_v1.mp3 differ diff --git a/game1/mp3/ambience/amb_kitchen_morning_v1.mp3 b/game1/mp3/ambience/amb_kitchen_morning_v1.mp3 new file mode 100644 index 0000000..b078374 Binary files /dev/null and b/game1/mp3/ambience/amb_kitchen_morning_v1.mp3 differ diff --git a/game1/mp3/ambience/amb_rain_window_01_v1.mp3 b/game1/mp3/ambience/amb_rain_window_01_v1.mp3 new file mode 100644 index 0000000..473affa Binary files /dev/null and b/game1/mp3/ambience/amb_rain_window_01_v1.mp3 differ diff --git a/game1/mp3/music/lv11_bgm_m1_main_loop_v1.mp3 b/game1/mp3/music/lv11_bgm_m1_main_loop_v1.mp3 new file mode 100644 index 0000000..3d01a59 Binary files /dev/null and b/game1/mp3/music/lv11_bgm_m1_main_loop_v1.mp3 differ diff --git a/game1/mp3/music/lv11_bgm_m2_suspense_v1.mp3 b/game1/mp3/music/lv11_bgm_m2_suspense_v1.mp3 new file mode 100644 index 0000000..cd469bc Binary files /dev/null and b/game1/mp3/music/lv11_bgm_m2_suspense_v1.mp3 differ diff --git a/game1/mp3/music/lv11_bgm_m3_zhounan_v1.mp3 b/game1/mp3/music/lv11_bgm_m3_zhounan_v1.mp3 new file mode 100644 index 0000000..81b2d1e Binary files /dev/null and b/game1/mp3/music/lv11_bgm_m3_zhounan_v1.mp3 differ diff --git a/game1/mp3/music/lv11_bgm_m4_ending_v1.mp3 b/game1/mp3/music/lv11_bgm_m4_ending_v1.mp3 new file mode 100644 index 0000000..0fa430b Binary files /dev/null and b/game1/mp3/music/lv11_bgm_m4_ending_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_anan_v1.mp3 b/game1/mp3/music/lv11_ring_anan_v1.mp3 new file mode 100644 index 0000000..4d325a2 Binary files /dev/null and b/game1/mp3/music/lv11_ring_anan_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_azhe_v1.mp3 b/game1/mp3/music/lv11_ring_azhe_v1.mp3 new file mode 100644 index 0000000..8985486 Binary files /dev/null and b/game1/mp3/music/lv11_ring_azhe_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_delivery_v1.mp3 b/game1/mp3/music/lv11_ring_delivery_v1.mp3 new file mode 100644 index 0000000..7b4b214 Binary files /dev/null and b/game1/mp3/music/lv11_ring_delivery_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_dorm_group_v1.mp3 b/game1/mp3/music/lv11_ring_dorm_group_v1.mp3 new file mode 100644 index 0000000..ff2b3f7 Binary files /dev/null and b/game1/mp3/music/lv11_ring_dorm_group_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_hr_v1.mp3 b/game1/mp3/music/lv11_ring_hr_v1.mp3 new file mode 100644 index 0000000..6ffe655 Binary files /dev/null and b/game1/mp3/music/lv11_ring_hr_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_mom_v1.mp3 b/game1/mp3/music/lv11_ring_mom_v1.mp3 new file mode 100644 index 0000000..87fc941 Binary files /dev/null and b/game1/mp3/music/lv11_ring_mom_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_unknown_v1.mp3 b/game1/mp3/music/lv11_ring_unknown_v1.mp3 new file mode 100644 index 0000000..6a8b1fd Binary files /dev/null and b/game1/mp3/music/lv11_ring_unknown_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_xiaomei_v1.mp3 b/game1/mp3/music/lv11_ring_xiaomei_v1.mp3 new file mode 100644 index 0000000..1de1dd1 Binary files /dev/null and b/game1/mp3/music/lv11_ring_xiaomei_v1.mp3 differ diff --git a/game1/mp3/music/lv11_ring_zhounan_v1.mp3 b/game1/mp3/music/lv11_ring_zhounan_v1.mp3 new file mode 100644 index 0000000..3764934 Binary files /dev/null and b/game1/mp3/music/lv11_ring_zhounan_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_breathing_unknown_v1.mp3 b/game1/mp3/sfx/sfx_breathing_unknown_v1.mp3 new file mode 100644 index 0000000..dbd3e48 Binary files /dev/null and b/game1/mp3/sfx/sfx_breathing_unknown_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_cat_yowl_v1.mp3 b/game1/mp3/sfx/sfx_cat_yowl_v1.mp3 new file mode 100644 index 0000000..1511547 Binary files /dev/null and b/game1/mp3/sfx/sfx_cat_yowl_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_deep_breath_v1.mp3 b/game1/mp3/sfx/sfx_deep_breath_v1.mp3 new file mode 100644 index 0000000..b94989d Binary files /dev/null and b/game1/mp3/sfx/sfx_deep_breath_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_door_knock_firm_v1.mp3 b/game1/mp3/sfx/sfx_door_knock_firm_v1.mp3 new file mode 100644 index 0000000..9941247 Binary files /dev/null and b/game1/mp3/sfx/sfx_door_knock_firm_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_door_knock_gentle_v1.mp3 b/game1/mp3/sfx/sfx_door_knock_gentle_v1.mp3 new file mode 100644 index 0000000..119c09e Binary files /dev/null and b/game1/mp3/sfx/sfx_door_knock_gentle_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_ending_chime_v1.mp3 b/game1/mp3/sfx/sfx_ending_chime_v1.mp3 new file mode 100644 index 0000000..6395e47 Binary files /dev/null and b/game1/mp3/sfx/sfx_ending_chime_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_glass_shatter_short_v1.mp3 b/game1/mp3/sfx/sfx_glass_shatter_short_v1.mp3 new file mode 100644 index 0000000..edaf152 Binary files /dev/null and b/game1/mp3/sfx/sfx_glass_shatter_short_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_heartbeat_fast_v1.mp3 b/game1/mp3/sfx/sfx_heartbeat_fast_v1.mp3 new file mode 100644 index 0000000..5a822ec Binary files /dev/null and b/game1/mp3/sfx/sfx_heartbeat_fast_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_kettle_whistle_v1.mp3 b/game1/mp3/sfx/sfx_kettle_whistle_v1.mp3 new file mode 100644 index 0000000..83b8ca8 Binary files /dev/null and b/game1/mp3/sfx/sfx_kettle_whistle_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_keyboard_fast_v1.mp3 b/game1/mp3/sfx/sfx_keyboard_fast_v1.mp3 new file mode 100644 index 0000000..899c876 Binary files /dev/null and b/game1/mp3/sfx/sfx_keyboard_fast_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_keyboard_slow_v1.mp3 b/game1/mp3/sfx/sfx_keyboard_slow_v1.mp3 new file mode 100644 index 0000000..51a6e48 Binary files /dev/null and b/game1/mp3/sfx/sfx_keyboard_slow_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_night_bus_v1.mp3 b/game1/mp3/sfx/sfx_night_bus_v1.mp3 new file mode 100644 index 0000000..0ad7bc4 Binary files /dev/null and b/game1/mp3/sfx/sfx_night_bus_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_paper_turning_v1.mp3 b/game1/mp3/sfx/sfx_paper_turning_v1.mp3 new file mode 100644 index 0000000..a2ab4e1 Binary files /dev/null and b/game1/mp3/sfx/sfx_paper_turning_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_phone_vibrate_v1.mp3 b/game1/mp3/sfx/sfx_phone_vibrate_v1.mp3 new file mode 100644 index 0000000..bd58ac7 Binary files /dev/null and b/game1/mp3/sfx/sfx_phone_vibrate_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_rain_heavier_v1.mp3 b/game1/mp3/sfx/sfx_rain_heavier_v1.mp3 new file mode 100644 index 0000000..12c93d3 Binary files /dev/null and b/game1/mp3/sfx/sfx_rain_heavier_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_rain_lighter_v1.mp3 b/game1/mp3/sfx/sfx_rain_lighter_v1.mp3 new file mode 100644 index 0000000..650f9a3 Binary files /dev/null and b/game1/mp3/sfx/sfx_rain_lighter_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_transition_chapter_v1.mp3 b/game1/mp3/sfx/sfx_transition_chapter_v1.mp3 new file mode 100644 index 0000000..f8b9666 Binary files /dev/null and b/game1/mp3/sfx/sfx_transition_chapter_v1.mp3 differ diff --git a/game1/mp3/sfx/sfx_water_boiling_v1.mp3 b/game1/mp3/sfx/sfx_water_boiling_v1.mp3 new file mode 100644 index 0000000..dfd4193 Binary files /dev/null and b/game1/mp3/sfx/sfx_water_boiling_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0015_mom_call_01_wav_v1.mp3 b/game1/mp3/tts/lv11_0015_mom_call_01_wav_v1.mp3 new file mode 100644 index 0000000..ab955a8 Binary files /dev/null and b/game1/mp3/tts/lv11_0015_mom_call_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0030_self3y_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_0030_self3y_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..f3b5631 Binary files /dev/null and b/game1/mp3/tts/lv11_0030_self3y_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0030_self3y_voice_02_wav_v1.mp3 b/game1/mp3/tts/lv11_0030_self3y_voice_02_wav_v1.mp3 new file mode 100644 index 0000000..c760746 Binary files /dev/null and b/game1/mp3/tts/lv11_0030_self3y_voice_02_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0030_self3y_voice_03_wav_v1.mp3 b/game1/mp3/tts/lv11_0030_self3y_voice_03_wav_v1.mp3 new file mode 100644 index 0000000..c16c063 Binary files /dev/null and b/game1/mp3/tts/lv11_0030_self3y_voice_03_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg1_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg1_wav_v1.mp3 new file mode 100644 index 0000000..fbc7b1c Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg1_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg2_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg2_wav_v1.mp3 new file mode 100644 index 0000000..dce6d7a Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg2_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg3_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg3_wav_v1.mp3 new file mode 100644 index 0000000..37672ac Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg3_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg4_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg4_wav_v1.mp3 new file mode 100644 index 0000000..1900d33 Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg4_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg5_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg5_wav_v1.mp3 new file mode 100644 index 0000000..86a666e Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg5_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg6_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg6_wav_v1.mp3 new file mode 100644 index 0000000..79e6ee5 Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg6_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg7_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg7_wav_v1.mp3 new file mode 100644 index 0000000..829ab95 Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg7_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_0200_mom_voice_01_seg8_wav_v1.mp3 b/game1/mp3/tts/lv11_0200_mom_voice_01_seg8_wav_v1.mp3 new file mode 100644 index 0000000..f45e7b8 Binary files /dev/null and b/game1/mp3/tts/lv11_0200_mom_voice_01_seg8_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2103_mom_call_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2103_mom_call_01_wav_v1.mp3 new file mode 100644 index 0000000..ba73fc7 Binary files /dev/null and b/game1/mp3/tts/lv11_2103_mom_call_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2115_xiaomei_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2115_xiaomei_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..96478de Binary files /dev/null and b/game1/mp3/tts/lv11_2115_xiaomei_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2115_xiaomei_voice_02_wav_v1.mp3 b/game1/mp3/tts/lv11_2115_xiaomei_voice_02_wav_v1.mp3 new file mode 100644 index 0000000..62681e3 Binary files /dev/null and b/game1/mp3/tts/lv11_2115_xiaomei_voice_02_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2115_xiaomei_voice_03_wav_v1.mp3 b/game1/mp3/tts/lv11_2115_xiaomei_voice_03_wav_v1.mp3 new file mode 100644 index 0000000..9405253 Binary files /dev/null and b/game1/mp3/tts/lv11_2115_xiaomei_voice_03_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2120_delivery_call_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2120_delivery_call_01_wav_v1.mp3 new file mode 100644 index 0000000..984a5cd Binary files /dev/null and b/game1/mp3/tts/lv11_2120_delivery_call_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2130_azhe_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2130_azhe_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..300a91d Binary files /dev/null and b/game1/mp3/tts/lv11_2130_azhe_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2145_hr_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2145_hr_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..eaca2e9 Binary files /dev/null and b/game1/mp3/tts/lv11_2145_hr_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2200_anan_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2200_anan_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..d7d1f86 Binary files /dev/null and b/game1/mp3/tts/lv11_2200_anan_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2215_dorm_a_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2215_dorm_a_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..fc607c0 Binary files /dev/null and b/game1/mp3/tts/lv11_2215_dorm_a_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2215_dorm_a_voice_02_wav_v1.mp3 b/game1/mp3/tts/lv11_2215_dorm_a_voice_02_wav_v1.mp3 new file mode 100644 index 0000000..9aad740 Binary files /dev/null and b/game1/mp3/tts/lv11_2215_dorm_a_voice_02_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2215_dorm_b_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2215_dorm_b_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..dd53219 Binary files /dev/null and b/game1/mp3/tts/lv11_2215_dorm_b_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2215_dorm_b_voice_02_wav_v1.mp3 b/game1/mp3/tts/lv11_2215_dorm_b_voice_02_wav_v1.mp3 new file mode 100644 index 0000000..c85edf8 Binary files /dev/null and b/game1/mp3/tts/lv11_2215_dorm_b_voice_02_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2215_dorm_c_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2215_dorm_c_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..6c08f4a Binary files /dev/null and b/game1/mp3/tts/lv11_2215_dorm_c_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg1_wav_v1.mp3 b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg1_wav_v1.mp3 new file mode 100644 index 0000000..c4df688 Binary files /dev/null and b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg1_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg2_wav_v1.mp3 b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg2_wav_v1.mp3 new file mode 100644 index 0000000..15b76e6 Binary files /dev/null and b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg2_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg3_wav_v1.mp3 b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg3_wav_v1.mp3 new file mode 100644 index 0000000..0cab5ec Binary files /dev/null and b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg3_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg4_wav_v1.mp3 b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg4_wav_v1.mp3 new file mode 100644 index 0000000..283603d Binary files /dev/null and b/game1/mp3/tts/lv11_2245_xiaomei_voice_01_seg4_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2300_mom_text_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2300_mom_text_01_wav_v1.mp3 new file mode 100644 index 0000000..0a001d7 Binary files /dev/null and b/game1/mp3/tts/lv11_2300_mom_text_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2315_azhe_call_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2315_azhe_call_01_wav_v1.mp3 new file mode 100644 index 0000000..bf2a0da Binary files /dev/null and b/game1/mp3/tts/lv11_2315_azhe_call_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2330_zhounan_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2330_zhounan_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..19520c7 Binary files /dev/null and b/game1/mp3/tts/lv11_2330_zhounan_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2345_zhounan_voice_01_wav_v1.mp3 b/game1/mp3/tts/lv11_2345_zhounan_voice_01_wav_v1.mp3 new file mode 100644 index 0000000..3725075 Binary files /dev/null and b/game1/mp3/tts/lv11_2345_zhounan_voice_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2345_zhounan_voice_02_wav_v1.mp3 b/game1/mp3/tts/lv11_2345_zhounan_voice_02_wav_v1.mp3 new file mode 100644 index 0000000..2f56c42 Binary files /dev/null and b/game1/mp3/tts/lv11_2345_zhounan_voice_02_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2345_zhounan_voice_03_wav_v1.mp3 b/game1/mp3/tts/lv11_2345_zhounan_voice_03_wav_v1.mp3 new file mode 100644 index 0000000..4550edf Binary files /dev/null and b/game1/mp3/tts/lv11_2345_zhounan_voice_03_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_2345_zhounan_voice_04_wav_v1.mp3 b/game1/mp3/tts/lv11_2345_zhounan_voice_04_wav_v1.mp3 new file mode 100644 index 0000000..a654c35 Binary files /dev/null and b/game1/mp3/tts/lv11_2345_zhounan_voice_04_wav_v1.mp3 differ diff --git a/game1/mp3/tts/lv11_sys_memo_01_wav_v1.mp3 b/game1/mp3/tts/lv11_sys_memo_01_wav_v1.mp3 new file mode 100644 index 0000000..22f07f8 Binary files /dev/null and b/game1/mp3/tts/lv11_sys_memo_01_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_a_linxia_wav_v1.mp3 b/game1/mp3/tts/v2_ending_a_linxia_wav_v1.mp3 new file mode 100644 index 0000000..bedb00d Binary files /dev/null and b/game1/mp3/tts/v2_ending_a_linxia_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_b_linxia_wav_v1.mp3 b/game1/mp3/tts/v2_ending_b_linxia_wav_v1.mp3 new file mode 100644 index 0000000..25931dc Binary files /dev/null and b/game1/mp3/tts/v2_ending_b_linxia_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_c_linxia_wav_v1.mp3 b/game1/mp3/tts/v2_ending_c_linxia_wav_v1.mp3 new file mode 100644 index 0000000..b264580 Binary files /dev/null and b/game1/mp3/tts/v2_ending_c_linxia_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_d_linxia_wav_v1.mp3 b/game1/mp3/tts/v2_ending_d_linxia_wav_v1.mp3 new file mode 100644 index 0000000..1a1a906 Binary files /dev/null and b/game1/mp3/tts/v2_ending_d_linxia_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_e_linxia_wav_v1.mp3 b/game1/mp3/tts/v2_ending_e_linxia_wav_v1.mp3 new file mode 100644 index 0000000..4157e7b Binary files /dev/null and b/game1/mp3/tts/v2_ending_e_linxia_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_ending_e_zhounan_wav_v1.mp3 b/game1/mp3/tts/v2_ending_e_zhounan_wav_v1.mp3 new file mode 100644 index 0000000..b3ce3fd Binary files /dev/null and b/game1/mp3/tts/v2_ending_e_zhounan_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_cold_fine_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_cold_fine_wav_v1.mp3 new file mode 100644 index 0000000..9b5d455 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_cold_fine_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_cold_know_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_cold_know_wav_v1.mp3 new file mode 100644 index 0000000..eab1222 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_cold_know_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_curious_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_curious_wav_v1.mp3 new file mode 100644 index 0000000..4a4ff71 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_hmm_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_hmm_wav_v1.mp3 new file mode 100644 index 0000000..ae87492 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_hmm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_ok_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_ok_wav_v1.mp3 new file mode 100644 index 0000000..f5f5a60 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_ok_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_then_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_then_wav_v1.mp3 new file mode 100644 index 0000000..112b1f0 Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_then_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_linxia_generic_warm_ok_wav_v1.mp3 b/game1/mp3/tts/v2_linxia_generic_warm_ok_wav_v1.mp3 new file mode 100644 index 0000000..1ef930c Binary files /dev/null and b/game1/mp3/tts/v2_linxia_generic_warm_ok_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg01_linxia_auto_wav_v1.mp3 b/game1/mp3/tts/v2_msg01_linxia_auto_wav_v1.mp3 new file mode 100644 index 0000000..ee1e95e Binary files /dev/null and b/game1/mp3/tts/v2_msg01_linxia_auto_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..b255a8a Binary files /dev/null and b/game1/mp3/tts/v2_msg02_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..c6eb5c8 Binary files /dev/null and b/game1/mp3/tts/v2_msg02_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..10f1acd Binary files /dev/null and b/game1/mp3/tts/v2_msg02_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..bdd1d6e Binary files /dev/null and b/game1/mp3/tts/v2_msg02_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_r3_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_r3_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..ba69bbf Binary files /dev/null and b/game1/mp3/tts/v2_msg02_r3_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_r3_react_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_r3_react_wav_v1.mp3 new file mode 100644 index 0000000..8e4cf0e Binary files /dev/null and b/game1/mp3/tts/v2_msg02_r3_react_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..d57ab7b Binary files /dev/null and b/game1/mp3/tts/v2_msg02_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..0687871 Binary files /dev/null and b/game1/mp3/tts/v2_msg02_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..7ac3711 Binary files /dev/null and b/game1/mp3/tts/v2_msg02_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..d4e91f8 Binary files /dev/null and b/game1/mp3/tts/v2_msg02_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg02_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg02_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..729809c Binary files /dev/null and b/game1/mp3/tts/v2_msg02_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg03_linxia_auto_wav_v1.mp3 b/game1/mp3/tts/v2_msg03_linxia_auto_wav_v1.mp3 new file mode 100644 index 0000000..12216d0 Binary files /dev/null and b/game1/mp3/tts/v2_msg03_linxia_auto_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..3f25573 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..44051d2 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..2f98073 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..b9924ef Binary files /dev/null and b/game1/mp3/tts/v2_msg04_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3c_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3c_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..64cbc51 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3c_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3c_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3c_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..1144657 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3c_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3c_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3c_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..7c17a91 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3c_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3w_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3w_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..373e258 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3w_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3w_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3w_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..d469d12 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3w_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3w_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3w_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..bed53f4 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3w_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3w_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3w_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..b077ccc Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3w_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_r3w_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_r3w_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..d63d290 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_r3w_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..40f82a8 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..c8f6570 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..7a16cb3 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..2e19929 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg04_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg04_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..9cac590 Binary files /dev/null and b/game1/mp3/tts/v2_msg04_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..5be3ef4 Binary files /dev/null and b/game1/mp3/tts/v2_msg05_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..42f0c0e Binary files /dev/null and b/game1/mp3/tts/v2_msg05_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..c39b88d Binary files /dev/null and b/game1/mp3/tts/v2_msg05_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..cae2d59 Binary files /dev/null and b/game1/mp3/tts/v2_msg05_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..da8b70a Binary files /dev/null and b/game1/mp3/tts/v2_msg05_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg05_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg05_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..65d24fe Binary files /dev/null and b/game1/mp3/tts/v2_msg05_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..8f9fa23 Binary files /dev/null and b/game1/mp3/tts/v2_msg06_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..4679fe0 Binary files /dev/null and b/game1/mp3/tts/v2_msg06_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..36b126a Binary files /dev/null and b/game1/mp3/tts/v2_msg06_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..986c64d Binary files /dev/null and b/game1/mp3/tts/v2_msg06_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..e49287d Binary files /dev/null and b/game1/mp3/tts/v2_msg06_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..1126cd2 Binary files /dev/null and b/game1/mp3/tts/v2_msg06_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..ff65d87 Binary files /dev/null and b/game1/mp3/tts/v2_msg06_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..ab08f60 Binary files /dev/null and b/game1/mp3/tts/v2_msg06_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg06_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg06_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..9e630be Binary files /dev/null and b/game1/mp3/tts/v2_msg06_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..ec54bc4 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..6b0c07f Binary files /dev/null and b/game1/mp3/tts/v2_msg07_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..35cb0f7 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_r3_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_r3_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..7b307a9 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_r3_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_r3_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_r3_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..ae83f85 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_r3_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_r3_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_r3_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..b8c987e Binary files /dev/null and b/game1/mp3/tts/v2_msg07_r3_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..24c8a42 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..e9cf2e0 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg07_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg07_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..203dee9 Binary files /dev/null and b/game1/mp3/tts/v2_msg07_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..f842aed Binary files /dev/null and b/game1/mp3/tts/v2_msg09_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..2190c0a Binary files /dev/null and b/game1/mp3/tts/v2_msg09_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..cdf9096 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..6f56481 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_r3_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_r3_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..2cea7d5 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_r3_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_r3_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_r3_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..3e52b25 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_r3_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_r3_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_r3_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..9619b57 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_r3_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_r3_react_silent_q_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_r3_react_silent_q_wav_v1.mp3 new file mode 100644 index 0000000..2be04fc Binary files /dev/null and b/game1/mp3/tts/v2_msg09_r3_react_silent_q_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_r3_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_r3_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..9ae5ff3 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_r3_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..9e88260 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..4891cf0 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg09_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg09_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..3d7ce10 Binary files /dev/null and b/game1/mp3/tts/v2_msg09_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..c90447c Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..1aa0411 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_mom_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_mom_wav_v1.mp3 new file mode 100644 index 0000000..67d61f5 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_mom_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..6b5a97d Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_react_down_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_react_down_wav_v1.mp3 new file mode 100644 index 0000000..b40fde5 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_react_down_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..62d541e Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_call_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_call_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..d3255e7 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_call_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..e4bf056 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..85db7ba Binary files /dev/null and b/game1/mp3/tts/v2_msg10_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..387aedd Binary files /dev/null and b/game1/mp3/tts/v2_msg10_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..137f860 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..f0f7e9e Binary files /dev/null and b/game1/mp3/tts/v2_msg10_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..4bacdf2 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..c4e37f9 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..c1f7617 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_rw_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_rw_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..edf0ed4 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_rw_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_rw_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_rw_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..62213ae Binary files /dev/null and b/game1/mp3/tts/v2_msg10_rw_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_rw_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_rw_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..40d1059 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_rw_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_rw_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_rw_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..36b7f7c Binary files /dev/null and b/game1/mp3/tts/v2_msg10_rw_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg10_rw_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg10_rw_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..5586814 Binary files /dev/null and b/game1/mp3/tts/v2_msg10_rw_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..880c397 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..897ae19 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..68fae6d Binary files /dev/null and b/game1/mp3/tts/v2_msg11_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..70fa7f8 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_r3_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_r3_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..6c8af63 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_r3_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..f28d879 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..2d70636 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..48ae195 Binary files /dev/null and b/game1/mp3/tts/v2_msg11_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg11_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg11_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..b794c8c Binary files /dev/null and b/game1/mp3/tts/v2_msg11_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..ea1aaeb Binary files /dev/null and b/game1/mp3/tts/v2_msg12_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..8239e17 Binary files /dev/null and b/game1/mp3/tts/v2_msg12_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..dd888aa Binary files /dev/null and b/game1/mp3/tts/v2_msg12_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..de8c3d2 Binary files /dev/null and b/game1/mp3/tts/v2_msg12_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..1d38cac Binary files /dev/null and b/game1/mp3/tts/v2_msg12_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..fae8afd Binary files /dev/null and b/game1/mp3/tts/v2_msg12_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..c724270 Binary files /dev/null and b/game1/mp3/tts/v2_msg12_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..0501fdd Binary files /dev/null and b/game1/mp3/tts/v2_msg12_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg12_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg12_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..30aa6c2 Binary files /dev/null and b/game1/mp3/tts/v2_msg12_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..eaf929a Binary files /dev/null and b/game1/mp3/tts/v2_msg13_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..02693c8 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_linxia_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_linxia_tap_wav_v1.mp3 new file mode 100644 index 0000000..3bd68e5 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_linxia_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..780319b Binary files /dev/null and b/game1/mp3/tts/v2_msg13_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_linxia_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_linxia_cold_wav_v1.mp3 new file mode 100644 index 0000000..0981656 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_linxia_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_linxia_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_linxia_curious_wav_v1.mp3 new file mode 100644 index 0000000..c0cfbf3 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_linxia_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_linxia_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_linxia_warm_wav_v1.mp3 new file mode 100644 index 0000000..a9db32f Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_linxia_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..12a65cf Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..6b2b01a Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_r3_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_r3_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..f64314e Binary files /dev/null and b/game1/mp3/tts/v2_msg13_r3_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_react_cold_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_react_cold_wav_v1.mp3 new file mode 100644 index 0000000..6f90571 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_react_cold_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_react_curious_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_react_curious_wav_v1.mp3 new file mode 100644 index 0000000..1f83e85 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_react_curious_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_react_silent_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_react_silent_wav_v1.mp3 new file mode 100644 index 0000000..326d9fa Binary files /dev/null and b/game1/mp3/tts/v2_msg13_react_silent_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_react_tap_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_react_tap_wav_v1.mp3 new file mode 100644 index 0000000..98a03e5 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_react_tap_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg13_react_warm_wav_v1.mp3 b/game1/mp3/tts/v2_msg13_react_warm_wav_v1.mp3 new file mode 100644 index 0000000..6bb7685 Binary files /dev/null and b/game1/mp3/tts/v2_msg13_react_warm_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg14_linxia_auto_wav_v1.mp3 b/game1/mp3/tts/v2_msg14_linxia_auto_wav_v1.mp3 new file mode 100644 index 0000000..efff5b3 Binary files /dev/null and b/game1/mp3/tts/v2_msg14_linxia_auto_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg14_mom_ask_wav_v1.mp3 b/game1/mp3/tts/v2_msg14_mom_ask_wav_v1.mp3 new file mode 100644 index 0000000..b498e6f Binary files /dev/null and b/game1/mp3/tts/v2_msg14_mom_ask_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg14_react_linked_wav_v1.mp3 b/game1/mp3/tts/v2_msg14_react_linked_wav_v1.mp3 new file mode 100644 index 0000000..8f821b9 Binary files /dev/null and b/game1/mp3/tts/v2_msg14_react_linked_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_msg14_react_unlinked_wav_v1.mp3 b/game1/mp3/tts/v2_msg14_react_unlinked_wav_v1.mp3 new file mode 100644 index 0000000..dad36e7 Binary files /dev/null and b/game1/mp3/tts/v2_msg14_react_unlinked_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_sys_content_warning_wav_v1.mp3 b/game1/mp3/tts/v2_sys_content_warning_wav_v1.mp3 new file mode 100644 index 0000000..608bbda Binary files /dev/null and b/game1/mp3/tts/v2_sys_content_warning_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_sys_hotline_wav_v1.mp3 b/game1/mp3/tts/v2_sys_hotline_wav_v1.mp3 new file mode 100644 index 0000000..def43b8 Binary files /dev/null and b/game1/mp3/tts/v2_sys_hotline_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_sys_paused_wav_v1.mp3 b/game1/mp3/tts/v2_sys_paused_wav_v1.mp3 new file mode 100644 index 0000000..112ae2d Binary files /dev/null and b/game1/mp3/tts/v2_sys_paused_wav_v1.mp3 differ diff --git a/game1/mp3/tts/v2_sys_wait_reply_wav_v1.mp3 b/game1/mp3/tts/v2_sys_wait_reply_wav_v1.mp3 new file mode 100644 index 0000000..f3669ca Binary files /dev/null and b/game1/mp3/tts/v2_sys_wait_reply_wav_v1.mp3 differ diff --git a/game1/操作说明.md b/game1/操作说明.md new file mode 100644 index 0000000..9601460 --- /dev/null +++ b/game1/操作说明.md @@ -0,0 +1,237 @@ +# 《林夏》操作说明 + +--- + +## 一、游戏简介 + +全黑屏叙事游戏。玩家扮演 24 岁的林夏,用一部碎屏手机度过今晚 21:00–02:00 的 5 个小时。 + +- **没有视觉界面**,只有声音和触感 +- **全程约 60 分钟**(5 小时游戏时间压缩) +- **16 条消息**,5 种结局 +- **不需要说话**,不需要麦克风 + +--- + +## 二、开始前准备 + +1. 手机和电脑连接**同一 Wi-Fi** +2. 打开手机浏览器,输入地址: + + ``` + http://172.28.107.97:8765/game/ + ``` + +3. **关灯,戴上耳机** +4. 将手机音量调到适中(建议 60–80%) +5. 轻触屏幕任意位置开始游戏 + +> **iOS 用户注意**:Safari 不支持震动反馈,操作正常但无震感。建议使用 Android Chrome。 + +--- + +## 三、消息类型与接收方式 + +游戏中有三种消息形态: + +### 来电 +- 触发:手机长震 + 角色专属铃声 +- 响 **20–30 秒**后自动漏接 + +| 操作 | 效果 | +|------|------| +| **单点** | 接听 | +| **左滑** | 拒接 | +| **不动** | 漏接(对方挂断) | + +### 微信语音 / 微信文字 +- 触发:两短震 + 系统提示音(TTS 报出发件人) + +| 操作 | 效果 | +|------|------| +| **单点** | 播放语音 / 念出文字 | +| **左滑** | 忽略(保持未读) | +| **不动** | 保持未读,晚些再听 | + +--- + +## 四、回复消息 + +**听完语音 / 文字念完后**,进入等待回复状态: + +| 操作 | 发送内容 | +|------|----------| +| **单点** | 发"嗯。"(最简单的回执) | +| **双点** | 发标准回复(针对该消息的一句话) | +| **长按 1 秒** | 进入**细回复**模式 | +| **左滑** | 已读不回 | +| **不动** | 维持"已读未回"状态 | + +--- + +## 五、细回复(核心机制) + +长按 1 秒后,震动确认进入细回复。系统会依次念出 **4 个候选回复**: + +``` +一…… "好,明天寄。" +二…… "你怎么不自己来拿。" +三…… "你那边……都好吗。" +四…… (什么都不说) +``` + +**在听到目标选项时,朝对应方向滑动:** + +| 滑动方向 | 对应选项 | +|----------|----------| +| **左滑** | 一 | +| **右滑** | 二 | +| **上滑** | 三 | +| **下滑** | 四 | + +> **没听清?** 单点屏幕可重听所有选项,或长按 1 秒重新播放。 +> 选错了也没关系——每条消息只影响行为画像,不会"game over"。 + +--- + +## 六、查看当前状态 + +**随时下滑**,系统会用语音告诉你当前在哪个页面,以及可以做什么操作。 + +例如: +- 主屏幕时下滑 → "主屏幕,3条未读。上滑查看收件箱。" +- 来电时下滑 → "妈妈来电中。单点接听,左滑拒接。" +- 听完消息后下滑 → "阿哲的消息已播完。单点回嗯,双点标准回复,长按细回复,左滑已读不回。" + +> 不确定自己在哪?下滑就对了。 + +--- + +## 七、查看未读列表(收件箱) + +在主屏幕**上滑**,进入收件箱模式。 + +系统会依次念出所有未读消息: +``` +"收件箱:4条未读。妈妈,来电。阿哲,语音。周南,语音。……" +``` + +- **单点** → 跳转至列表第一条 +- **左滑** → 返回主屏幕 +- **等待 8 秒** → 自动关闭收件箱,返回游戏 + +--- + +## 八、游戏内时间 + +游戏将现实的 21:00–02:00(5 小时)压缩为 **60 分钟**真实时间。 + +| 游戏时间 | 真实等待 | +|----------|----------| +| 21:03 | 约 36 秒 | +| 21:30 | 约 6 分钟 | +| 22:30 | 约 18 分钟 | +| 23:45 | 约 33 分钟 | +| 02:00 | 约 60 分钟 | + +消息到来时间固定,**漏接 / 不听是合法选择**,但漏掉的内容不会重发。 + +--- + +## 九、结局说明(不含剧透) + +共 **5 种结局**,由以下 5 个变量决定: + +| 变量 | 触发条件 | +|------|----------| +| 与妈妈的连接 | 是否接了妈妈的电话 / 回了文字 | +| 阿哲是否回来 | 23:15 那通电话的选择 | +| 群里是否发言 | 寝室群消息的回应 | +| 与周南的深度 | 回应周南的次数与方式 | +| 是否听自己 | 00:30 时光胶囊是否播放 | + +另有一个**隐藏结局 E**,需要与某位角色深度互动才能触发。 + +--- + +## 十、行为画像 + +游戏全程追踪三个维度(玩家不可见): + +| 维度 | 含义 | 触发行为 | +|------|------|----------| +| **avoidance**(回避) | 林夏今晚想一个人待着 | 漏接、不回、已读不回 | +| **engagement**(投入) | 林夏在认真面对每一个人 | 细回复、主动追问 | +| **nostalgia**(怀旧) | 林夏在这一夜反复回望 | 重听同一条消息、分享自己 | + +画像决定 **00:30 时光胶囊**播放哪个版本(明朗 / 迷茫 / 温柔)。 + +--- + +## 十一、彩蛋 + +- **夜间启动**(现实时间 22:00–04:00 之间打开游戏):开场多一句话 +- **消息09**:小美醉语音结束后会有一个撤回事件 +- **消息04**:如果一直不回阿哲,会听到一个小细节 + +--- + +## 十二、开发者 / 测试模式 + +在 URL 末尾加 `?dev` 可开启**10倍速**模式: + +``` +http://172.28.107.97:8765/game/?dev +``` + +- 所有消息的触发时间缩短为原来的 1/10 +- 全程约 **6 分钟**可打通 +- 适合测试结局分支 + +--- + +## 十三、启动服务器 + +关机重启后需要重新启动 HTTP 服务器: + +```bash +cd /home/xsl/blind +python3 -m http.server 8765 --bind 0.0.0.0 & +``` + +查看当前 IP: + +```bash +hostname -I | awk '{print $1}' +``` + +--- + +## 十四、文件结构 + +``` +/home/xsl/blind/ +├── game/ +│ ├── index.html 主页面(黑屏) +│ ├── manifest.json PWA 配置 +│ ├── 操作说明.md 本文件 +│ └── js/ +│ ├── utils.js 工具函数 + 浏览器 TTS +│ ├── haptics.js 震动反馈 +│ ├── audio.js 音频管理器 +│ ├── gestures.js 单指手势检测 +│ ├── profile.js 行为画像评分 +│ ├── story.js 16条消息数据 +│ ├── engine.js 游戏状态机 +│ └── main.js 入口 +└── audio/ + └── 00_raw/ + ├── tts/ 角色语音(68条) + ├── music/ BGM + 铃声 + ├── sfx/ 音效 + └── ambience/ 环境底噪 +``` + +--- + +*"屏幕坏了,但她的一夜还没结束。"* diff --git a/voice/hr/hr_extra_18_trimmed.wav b/voice/hr/hr_extra_18_trimmed.wav new file mode 100644 index 0000000..3a5338d Binary files /dev/null and b/voice/hr/hr_extra_18_trimmed.wav differ