v2收尾:手势升级 + 暂停退出 + 结局语音化 + 分支补全 + 12条新音频
gestures.js: 新增长按(1s)、两指长按(暂停)、三指点击(退出),支持多指检测 engine.js: REPLY_COUNT变量、长按重播/状态广播、暂停恢复退出机制、 选择提示音、结局台词预录音频替换TTS、内容预警+心理热线 story.js: MSG-10/11 follow-up补全down(沉默)选项 index.html: 操作指南添加长按/安全手势、内容预警文字 batch_tts_voxcpm.py: 新增12条台词(结局旁白+系统提示+分支NPC反应) audio/mp3/tts: 12个VoxCPM2生成的林夏声线MP3 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,14 @@
|
||||
<div class="ctrl-group">
|
||||
<div class="ctrl-scene">播放中</div>
|
||||
<div class="ctrl-row"><span class="ctrl-gesture">双击</span><span class="ctrl-action">跳过</span></div>
|
||||
<div class="ctrl-row"><span class="ctrl-gesture">长按</span><span class="ctrl-action">重播</span></div>
|
||||
</div>
|
||||
|
||||
<div class="ctrl-group">
|
||||
<div class="ctrl-scene">随时可用</div>
|
||||
<div class="ctrl-row"><span class="ctrl-gesture">两指长按</span><span class="ctrl-action">暂停</span></div>
|
||||
<div class="ctrl-row"><span class="ctrl-gesture">三指点击</span><span class="ctrl-action">退出(暂停后)</span></div>
|
||||
<div class="ctrl-row"><span class="ctrl-gesture">长按</span><span class="ctrl-action">播报未读数</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -130,6 +138,10 @@
|
||||
建议关灯 · 戴上耳机<br>
|
||||
按你的节奏来
|
||||
</div>
|
||||
<div class="tip" style="margin-top:20px;color:#333;">
|
||||
本游戏涉及孤独、家庭关系等情感话题<br>
|
||||
请在舒适的状态下体验
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="caption"></div>
|
||||
|
||||
+127
-16
@@ -6,6 +6,7 @@
|
||||
// 新增状态:
|
||||
// responding — 林夏说话中(打字音效 + 语音播放)
|
||||
// reacting — NPC反应播放中
|
||||
// paused — 游戏暂停(两指长按触发)
|
||||
|
||||
class GameEngine {
|
||||
constructor() {
|
||||
@@ -20,6 +21,7 @@ class GameEngine {
|
||||
ZHOUNAN_SHARE: false,
|
||||
SELF_RECORD: false,
|
||||
UNREAD: 0,
|
||||
REPLY_COUNT: 0,
|
||||
};
|
||||
|
||||
this.profile = new ProfileTracker();
|
||||
@@ -35,6 +37,9 @@ class GameEngine {
|
||||
this._pendingResolve = null; // 用于中断语音播放的 resolve
|
||||
this._skipRequested = false; // 跳过标志
|
||||
|
||||
// 暂停系统
|
||||
this._pausedState = null; // 暂停前的状态
|
||||
|
||||
this.gest = null;
|
||||
}
|
||||
|
||||
@@ -49,10 +54,11 @@ class GameEngine {
|
||||
idle: '',
|
||||
notification: '单击 播放 · 双击 跳过',
|
||||
ringing: '单击 接听 · 左滑 拒接',
|
||||
playing: '双击 跳过',
|
||||
playing: '双击 跳过 · 长按 重播',
|
||||
choosing: '→温暖 ←冷淡 ↑追问 ↓沉默',
|
||||
responding: '双击 跳过',
|
||||
reacting: '双击 跳过',
|
||||
paused: '单击 继续 · 三指点击 退出',
|
||||
ending: '',
|
||||
};
|
||||
el.textContent = H[s] || '';
|
||||
@@ -65,17 +71,24 @@ class GameEngine {
|
||||
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('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 });
|
||||
@@ -334,6 +347,7 @@ class GameEngine {
|
||||
this.state = 'choosing';
|
||||
SFX_UI.choiceReady();
|
||||
Haptic.confirm();
|
||||
Snd.playVoice([`${T}/v2_sys_wait_reply_wav_v1.mp3`]);
|
||||
this._startReminder();
|
||||
}
|
||||
|
||||
@@ -369,6 +383,7 @@ class GameEngine {
|
||||
// 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);
|
||||
@@ -516,6 +531,13 @@ class GameEngine {
|
||||
|
||||
_onTap() {
|
||||
const s = this.state;
|
||||
|
||||
// 暂停中 → 恢复
|
||||
if (s === 'paused') {
|
||||
this._onResume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (s === 'ringing') {
|
||||
this._answerCall(this.currentMsg);
|
||||
} else if (s === 'notification') {
|
||||
@@ -530,6 +552,8 @@ class GameEngine {
|
||||
_onDoubleTap() {
|
||||
const s = this.state;
|
||||
|
||||
if (s === 'paused') return;
|
||||
|
||||
if (s === 'ringing') {
|
||||
this._rejectCall(this.currentMsg);
|
||||
return;
|
||||
@@ -579,6 +603,8 @@ class GameEngine {
|
||||
_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);
|
||||
@@ -602,6 +628,83 @@ class GameEngine {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 长按:重播 / 状态广播 ──
|
||||
_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);
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════
|
||||
// 结局系统
|
||||
// ══════════════════════════════════════════
|
||||
@@ -611,30 +714,29 @@ class GameEngine {
|
||||
|
||||
const v = this.vars;
|
||||
|
||||
// 结局E(隐藏)
|
||||
// 结局E(隐藏)— 优先级 1
|
||||
if (v.ZHOUNAN_DEPTH >= 2 && v.ZHOUNAN_SHARE &&
|
||||
(this.profile.label === 'engagement' || this.profile.label === 'nostalgia')) {
|
||||
return this._triggerEnding('E');
|
||||
}
|
||||
|
||||
// 结局A:妈妈连接 + 自己录音
|
||||
// 结局A:妈妈连接 + 自己录音 — 优先级 2
|
||||
if (v.MOM_LINK && v.SELF_RECORD) {
|
||||
return this._triggerEnding('A');
|
||||
}
|
||||
|
||||
// 结局B:拒了阿哲 + 回了周南
|
||||
// 结局B:拒了阿哲 + 回了周南 — 优先级 3
|
||||
if (v.HE_BACK === false && v.ZHOUNAN_DEPTH >= 1) {
|
||||
return this._triggerEnding('B');
|
||||
}
|
||||
|
||||
// 结局C:全部已读但极少回复
|
||||
const replied = Object.values(this.msgState).filter(s => s === 'replied').length;
|
||||
const read = Object.values(this.msgState).filter(s => s !== 'unread').length;
|
||||
if (read >= MESSAGES.length - 2 && replied <= 2) {
|
||||
// 结局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(兜底)
|
||||
// 结局D(兜底)— 优先级 5
|
||||
this._triggerEnding('D');
|
||||
}
|
||||
|
||||
@@ -659,6 +761,10 @@ class GameEngine {
|
||||
E: () => this._endingE(),
|
||||
}[type];
|
||||
if (fn) await fn();
|
||||
|
||||
// 结局后播报心理支持热线
|
||||
await sleep(3000);
|
||||
await this._playVoiceAsync([`${T}/v2_sys_hotline_wav_v1.mp3`]);
|
||||
}
|
||||
|
||||
async _endingA() {
|
||||
@@ -668,13 +774,15 @@ class GameEngine {
|
||||
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('寄出。');
|
||||
this._showCaption('寄出去了。');
|
||||
await this._playVoiceAsync([`${T}/v2_ending_b_linxia_wav_v1.mp3`]);
|
||||
}
|
||||
|
||||
async _endingC() {
|
||||
@@ -682,6 +790,7 @@ class GameEngine {
|
||||
SFX_UI.ending();
|
||||
await sleep(1000);
|
||||
this._showCaption('今晚就这样。');
|
||||
await this._playVoiceAsync([`${T}/v2_ending_c_linxia_wav_v1.mp3`]);
|
||||
}
|
||||
|
||||
async _endingD() {
|
||||
@@ -692,6 +801,7 @@ class GameEngine {
|
||||
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() {
|
||||
@@ -704,6 +814,7 @@ class GameEngine {
|
||||
SFX_UI.ending();
|
||||
await sleep(1000);
|
||||
this._showCaption('好。');
|
||||
await this._playVoiceAsync([`${T}/v2_ending_e_linxia_wav_v1.mp3`]);
|
||||
}
|
||||
|
||||
_showCaption(text) {
|
||||
|
||||
+150
-9
@@ -1,7 +1,8 @@
|
||||
// gestures.js — 触控手势检测器(简化版)
|
||||
// gestures.js — 触控手势检测器
|
||||
//
|
||||
// 仅支持 6 种手势:单击 · 双击 · 左滑 · 右滑 · 上滑 · 下滑
|
||||
// 无长按,无多指操作
|
||||
// 支持 9 种手势:
|
||||
// 单击 · 双击 · 长按(1s) · 左滑 · 右滑 · 上滑 · 下滑
|
||||
// 两指长按(1s) · 三指点击
|
||||
|
||||
class GestureDetector {
|
||||
constructor(el) {
|
||||
@@ -14,6 +15,15 @@ class GestureDetector {
|
||||
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();
|
||||
@@ -30,21 +40,105 @@ class GestureDetector {
|
||||
// ── 触摸事件 ──
|
||||
_bindTouch() {
|
||||
const el = this._el;
|
||||
|
||||
el.addEventListener('touchstart', e => {
|
||||
e.preventDefault();
|
||||
const t = e.touches[0];
|
||||
this._startX = t.clientX;
|
||||
this._startY = t.clientY;
|
||||
this._startTime = Date.now();
|
||||
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._reset(), { passive: false });
|
||||
el.addEventListener('touchcancel', () => {
|
||||
this._cancelLongPress();
|
||||
this._cancelMultiTouchLP();
|
||||
this._resetMultiTouch();
|
||||
this._reset();
|
||||
}, { passive: false });
|
||||
}
|
||||
|
||||
// ── 鼠标事件(桌面调试)──
|
||||
@@ -53,10 +147,31 @@ class GestureDetector {
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── 键盘事件(桌面调试)──
|
||||
@@ -69,11 +184,14 @@ class GestureDetector {
|
||||
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;
|
||||
@@ -114,8 +232,31 @@ class GestureDetector {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 工具方法 ──
|
||||
|
||||
_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();
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -388,6 +388,11 @@ const MESSAGES = [
|
||||
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 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -415,7 +420,8 @@ const MESSAGES = [
|
||||
},
|
||||
down: {
|
||||
isSilence: true,
|
||||
npcReact: [rx('v2_msg10_call_react_silent_wav_v1.mp3')],
|
||||
npcReact: [rx('v2_msg10_call_react_down_wav_v1.mp3')],
|
||||
profile: { avoidance: 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -469,6 +475,12 @@ const MESSAGES = [
|
||||
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 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user