// games/yisheng.js — 《遗声》 // 陌生人的手机,十五条录音。 // 单击=听这条,双击=跳过。 // 跳过就永远不知道这条说了什么。 // 结局由你听了多少、听了哪些决定。 const GAME_YISHENG = { id: 'yisheng', intro: '你收到了一部手机。手机的主人去世了一个月前。他留下了很多录音,按时间排列。你不认识他。或者你以为你不认识他。单击,听这条录音。双击,跳过,永远不知道这条说了什么。', first: 'r01', bgm: null, ambience: null, initialState: { heard: [], skipped: [], heard_critical: 0, // 听了几条关键录音(r10-r14) unlocked_last: false, }, scenes: { // ── 第1条:三月五日 ── r01: { narrate: '第一条录音。录制时间:三月五日,早上八点。时长:二十二秒。文件名:买橙子。', tap: { label: '听', narrate: '他说:今天买了一袋橙子,是脐橙,比上次的甜很多。建议大家有机会可以试试。就这些。录音结束。', state: s => ({ heard: [...s.heard, '买橙子'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r02', }, doubleTap: { label: '跳过', narrate: '你跳过了第一条。你永远不会知道这条说了什么了。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第一条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r02', }, }, // ── 第2条:工资日 ── r02: { narrate: '第二条录音。三月十二日,下午。时长:三十八秒。文件名:发工资了。', tap: { label: '听', narrate: '他说:今天发工资了。然后列了他这个月的支出清单,很详细——房租、电费、手机月供、还有给他妈买了一件外套。他说最后剩了不多,但够。录音结束。', state: s => ({ heard: [...s.heard, '发工资了'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r03', }, doubleTap: { label: '跳过', narrate: '你跳过了第二条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第二条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r03', }, }, // ── 第3条:工作烦心事 ── r03: { narrate: '第三条录音。三月十八日,晚上。时长:一分零七秒。文件名:说说工作的事。', tap: { label: '听', narrate: '他说他们组里来了个新同事,总是在会议上抢着发言,说了很多他本来准备说的话。他说他当时没说话,他不确定那是不是对的选择。他在录音里问自己:我是懦弱了,还是留有余地?他没有答案。录音结束。', state: s => ({ heard: [...s.heard, '工作的烦恼'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r04', }, doubleTap: { label: '跳过', narrate: '你跳过了第三条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第三条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r04', }, }, // ── 第4条:和同事吵架 ── r04: { narrate: '第四条录音。四月二日。时长:四十九秒。文件名:吵了一架。', tap: { label: '听', narrate: '他说他今天和那个新同事正面冲突了,是在走廊,两个人都没控制住。他说他说了一句话,事后觉得说得太重了。他在录音里把那句话又说了一遍,想听听是不是真的太重。录音里他沉默了一会儿,然后说:是的,是太重了。录音结束。', state: s => ({ heard: [...s.heard, '吵了一架'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r05', }, doubleTap: { label: '跳过', narrate: '你跳过了第四条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第四条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r05', }, }, // ── 第5条:电影 ── r05: { narrate: '第五条录音。四月十五日,深夜。时长:二十六秒。文件名:电影。', tap: { label: '听', narrate: '他说他去看了一部很老的电影,黑白的,在一个小影院,观众只有六个人。他说他中途哭了,但他不确定是因为电影,还是因为电影院里那种空荡荡的感觉。录音结束。', state: s => ({ heard: [...s.heard, '老电影'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r06', }, doubleTap: { label: '跳过', narrate: '你跳过了第五条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第五条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r06', }, }, // ── 第6条:小林 ── r06: { narrate: '第六条录音。五月三日。时长:一分二十秒。文件名:小林的事。', tap: { label: '听', narrate: '他开始讲一个叫小林的朋友。他说小林是他认识最久的人,从小一起长大的,后来各自去了不同的城市,联系越来越少。他说他最近一直在想,那种联系的稀薄,是谁的责任?还是说这就是长大的代价?录音结束。', state: s => ({ heard: [...s.heard, '小林的事'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r07', }, doubleTap: { label: '跳过', narrate: '你跳过了第六条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第六条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r07', }, }, // ── 第7条:小林的一句话 ── r07: { narrate: '第七条录音。五月二十日。时长:三十三秒。文件名:小林说的。', tap: { label: '听', narrate: '他说小林打电话来了。小林在电话里说了一句话,让他很难受。小林说:感觉你现在不太一样了,变得……不知道,挺难接近的。他说他当时说了没什么,你想多了。他说他那时候应该说:我只是最近状态不好。但他没说。录音结束。', state: s => ({ heard: [...s.heard, '小林说的话'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r08', }, doubleTap: { label: '跳过', narrate: '你跳过了第七条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第七条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r08', }, }, // ── 第8条:感情结束了 ── r08: { narrate: '第八条录音。六月八日,凌晨。时长:两分十四秒。文件名:结束了。', tap: { label: '听', narrate: '他说一段感情结束了,他没有细说是谁,说了有多久,只说:结束了,是我提的,我觉得这是对的,但今晚我睡不着。他说他在厨房坐着,泡了杯茶,但茶凉了也没喝。他说:我只是想把今晚的感觉记下来,不想让它消失。录音结束。', state: s => ({ heard: [...s.heard, '感情结束了'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r09', }, doubleTap: { label: '跳过', narrate: '你跳过了第八条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第八条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r09', }, }, // ── 第9条:是不是我的错 ── r09: { narrate: '第九条录音。六月二十日。时长:一分五十秒。文件名:在反思。', tap: { label: '听', narrate: '他说他一直在想那段感情里他做错了什么。他列了很多条,每一条都很具体。然后他说:但是我说不清,这些错是因为我是这样的人,还是因为那时候我在经历别的事情,所以才这样。他说:这个问题很重要,但我没有答案。录音结束。', state: s => ({ heard: [...s.heard, '反思'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r10', }, doubleTap: { label: '跳过', narrate: '你跳过了第九条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第九条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r10', }, }, // ── 第10条(关键):有人问起你 ── r10: { narrate: '第十条录音。七月四日。时长:四十二秒。文件名:有人问起你。', tap: { label: '听', narrate: '他说:今天有人跟我提到了你的名字。我以为我早就忘了,但我发现我还记得很多细节。他没有解释"你"是谁。他说:我觉得我应该把这件事录下来,因为我发现我不想忘记。录音结束。', state: s => ({ heard: [...s.heard, '有人问起你'], skipped: s.skipped, heard_critical: s.heard_critical + 1, unlocked_last: s.unlocked_last }), next: 'r11', }, doubleTap: { label: '跳过', narrate: '你跳过了第十条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第十条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r11', }, }, // ── 第11条(关键):他查了你 ── r11: { narrate: '第十一条录音。七月十一日。时长:一分零八秒。文件名:我查了一下。', tap: { label: '听', narrate: '他说:我查了你现在在哪里,在做什么。不是恶意,就是想知道。他说他找到了一些信息,知道了你现在的大致状态。他说:你好像过得还不错,我很高兴,也有一点……他停了,然后说:没什么。录音结束。', state: s => ({ heard: [...s.heard, '他查了你'], skipped: s.skipped, heard_critical: s.heard_critical + 1, unlocked_last: s.unlocked_last }), next: 'r12', }, doubleTap: { label: '跳过', narrate: '你跳过了第十一条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第十一条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r12', }, }, // ── 第12条(关键):如果你听到 ── r12: { narrate: '第十二条录音。八月二日。时长:五十七秒。文件名:给不认识我的人(草稿)。', tap: { label: '听', narrate: '他说:如果你听到这条,你肯定不认识我。我在想,把这些录音留给一个陌生人,有什么意义。然后他说:也许是因为我希望有人知道我活过,而不是认识我的人,而是真正陌生的人——你不需要对我有感情,你只是听了。录音结束。', state: s => ({ heard: [...s.heard, '给陌生人的草稿'], skipped: s.skipped, heard_critical: s.heard_critical + 1, unlocked_last: s.unlocked_last }), next: 'r13', }, doubleTap: { label: '跳过', narrate: '你跳过了第十二条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第十二条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r13', }, }, // ── 第13条(关键):一件事 ── r13: { narrate: '第十三条录音。九月一日。时长:两分三十八秒。文件名:我有一件事想说。', tap: { label: '听', narrate: '他深吸一口气,说:有一件事我从没对任何人说过。他停了很久,然后说:我有时候觉得活着的意义我不太找得到,不是说我要做什么,只是我不知道我在这里有什么用。他说:我知道这句话很沉,但我必须把它说出来,因为放在心里太久了。然后他说:我今天状态还可以,就是今天有这个力气把它说出来。录音结束。', state: s => ({ heard: [...s.heard, '那件事'], skipped: s.skipped, heard_critical: s.heard_critical + 1, unlocked_last: s.unlocked_last }), next: 'r14', }, doubleTap: { label: '跳过', narrate: '你跳过了第十三条。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第十三条'], heard_critical: s.heard_critical, unlocked_last: s.unlocked_last }), next: 'r14', }, }, // ── 第14条(关键):最后一条 ── r14: { narrate: '第十四条录音。十月十五日,录制时间是他去世前三天。时长:三分二十秒。文件名:最后一条,我想讲完整。', tap: { label: '听', narrate: '他说:我知道这是最后一条了。我不是悲观,我只是知道。他说:我想对听这些录音的人说,我不后悔我活过的大多数时候。橙子是甜的,老电影是值得哭的,小林的声音我还记得,那个人,不管怎样,我不后悔爱过。他说:如果你听了很多条,谢谢你。你是陌生人,但你陪着我说完了。录音结束。', state: s => ({ heard: [...s.heard, '最后一条'], skipped: s.skipped, heard_critical: s.heard_critical + 1, unlocked_last: s.heard.length >= 9, }), next: s => s.heard.length >= 9 ? 'r15' : null, }, doubleTap: { label: '跳过', narrate: '你跳过了第十四条,也就是最后一条。手机里没有更多录音了。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '第十四条'], heard_critical: s.heard_critical, unlocked_last: false }), next: null, }, }, // ── 第15条(隐藏):给不认识我的人 ── r15: { delay: 2000, narrate: '还有一条录音,没有标日期。文件名:给不认识我的人(正式版)。这条需要你听了很多条才能解锁。你解锁了。', tap: { label: '听', narrate: '他说:你好。你不认识我,我也不认识你。但你坐在那里,听完了我这些年说的话。我不知道你是谁,我不知道你们那边现在是白天还是夜晚。我只是想说:谢谢你愿意听一个陌生人说话。这很重要,比你知道的还要重要。录音结束。这是最后一条了。', state: s => ({ heard: [...s.heard, '给不认识我的人'], skipped: s.skipped, heard_critical: s.heard_critical, unlocked_last: true }), next: null, }, doubleTap: { label: '跳过', narrate: '你连最后这条也跳过了。', state: s => ({ heard: s.heard, skipped: [...s.skipped, '最后一条'], heard_critical: s.heard_critical, unlocked_last: false }), next: null, }, }, }, getEnding: s => { if (s.unlocked_last) return 'known'; if (s.heard_critical === 0) return 'stranger'; if (s.skipped.length >= 7) return 'passing'; if (s.heard.length >= 9) return 'outline'; return 'brief'; }, endings: { known: { narrate: '《我认识你》。你听完了他大部分的录音,你听到了那条隐藏的最后一条。你不认识他,但你陪他把该说的都说完了。这已经足够了。', }, stranger: { narrate: '《陌生人》。你跳过了所有关于他和你之间联系的录音。他对你来说,还是一个完全的陌生人。也许这样也好。', }, passing: { narrate: '《路过》。你路过了他的大部分录音,只停留了几条。你知道他存在过,但你不知道他是谁。', }, outline: { narrate: '《轮廓》。你听了他生活的碎片,知道了一个大致的形状。你不知道他所有的事,但你知道了一个人活着的样子。', }, brief: { narrate: '《简短的相遇》。你听了几条,然后停下了。也许你听到了你需要听的,也许你还没准备好听更多。这也是一种结果。', }, }, };