feat(看板娘): 她会记得前几天被你惹生气、被摸过头,今天第一次点她时翻一次旧账;好感升档那天说一句「熟了一点」

- 只看 7 天内、今天以前的事,同一件事只翻一次(之后说过那句就不再提);顺序是升档 > 惹生气 > 摸头。
- 只在闲聊类情况(空白题目页、题目列表、打招呼、夸人)翻,错了、卡住时照常说正事。
- 好感档位照样不显示,「熟了一点」是唯一的暗示。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-11-04 19:00:40 +08:00
1 parent 47c0b5464d
commit aa8a3b8bfc
5 files changed
+112 -5

No files matched your search

+3 -2
View File
@@ -12,7 +12,8 @@
* - 点一下冒气泡:一句话加最多三个按钮,按页面、按情况变(页面经 shared/mascot/guide.ts 告诉她),
* 台词在 shared/mascot/lines.ts。比赛里点她不弹气泡。再点一下、点别处、换页面都收起。
* - 对学生按行为挑话(常犯的错、今天做了几道、熟不熟,见 shared/mascot/behavior.ts)。好感按一共做对几道分五档,
* 高档多几组软一点的话、也更耐烦(档位不显示);
* 高档多几组软一点的话、也更耐烦(档位不显示)。跨天记得几件事(前几天惹她生气、摸过头、今天升了档),
* 今天第一次闲聊时翻一次旧账;
* 题目页上有几件事她会主动开口,频率上限在下面 SPEAK_GAP_MS。
* - 互动都记进 mascot_event(点开、点按钮、主动开口、摸头、嫌烦、被拖走)。
* - 一句一句地刷(两次点开隔不到 BURST_GAP_MS):第 3 次起不耐烦、第 5 次起炸毛、第 7 次背过身去,
@@ -329,7 +330,7 @@ const TIME_CHANCE = 0.15
function pickFor(guide: MascotGuide) {
let situation = guide.situation
if (!SERIOUS.has(situation) && !PESTERED.has(situation) && guide.n === undefined && !guide.vars) {
if (!SERIOUS.has(situation) && !PESTERED.has(situation) && situation !== 'memory.closer' && guide.n === undefined && !guide.vars) {
const timely = timeSituation()
if (Math.random() < RARE_CHANCE) situation = 'rare'
else if (timely && !userStore.isTeacherOrAbove && Math.random() < TIME_CHANCE) situation = timely
+32 -1
View File
@@ -109,7 +109,9 @@ const PRAISE = new Set<MascotSituation>(['problem.accepted', 'problem.firstTry',
const AFFINITY_TIERS = [10, 25, 40, 100] as const
/** 0 是还不熟(没有额外的话),1~4 对应 lines.ts 的 affinity.1~4。老师、没拉到数都是 0 */
export function affinityTier() {
const solved = mascotProfile.value?.solved ?? 0
return tierOf(mascotProfile.value?.solved ?? 0)
}
function tierOf(solved: number) {
return AFFINITY_TIERS.filter((min) => solved >= min).length
}
const AFFINITY_CHANCE = 0.25
@@ -135,12 +137,41 @@ function affinitySituation(tier: number): MascotSituation {
return `affinity.${level}` as MascotSituation
}
/** 这一页会话里翻过的旧账:说完到下次拉回新数之间别再说一遍 */
const memorySaid = new Set<'closer' | 'grudge' | 'pat'>()
function whenText(days: number) {
return days === 1 ? '昨天' : days === 2 ? '前天' : '前几天'
}
/** 跨天记得的事,有就挑一件:今天升档 > 被惹生气 > 被摸头。每件只翻一次(后端看说没说过) */
function memoryGuide(profile: MascotProfile): Pick<MascotGuide, 'situation' | 'vars'> | null {
const memory = profile.memory
if (!memory.closerSaidToday && !memorySaid.has('closer') && tierOf(memory.solvedBeforeToday) < tierOf(profile.solved)) {
memorySaid.add('closer')
return { situation: 'memory.closer' }
}
if (memory.grudgeDaysAgo !== null && !memorySaid.has('grudge')) {
memorySaid.add('grudge')
return { situation: 'memory.grudge', vars: { when: whenText(memory.grudgeDaysAgo) } }
}
if (memory.patDaysAgo !== null && !memorySaid.has('pat')) {
memorySaid.add('pat')
return { situation: 'memory.pat', vars: { when: whenText(memory.patDaysAgo) } }
}
return null
}
/** 点她的时候:按行为把页面给的情况换成更贴这个学生的那一组(按钮不变) */
export function personalize(guide: MascotGuide): MascotGuide {
const profile = mascotProfile.value
if (!profile) return guide
if (profile.pokes + sessionPokes === 0) return { ...guide, situation: 'first.meet', n: undefined, vars: undefined }
const situation = guide.situation
if (CHATTY.has(situation)) {
const memory = memoryGuide(profile)
if (memory) return { ...guide, ...memory, n: undefined }
}
// 常点「太难了」的,错了先软着说,不翻老毛病
if (FAILURES.has(situation) && profile.tooHard >= GENTLE_TOO_HARD && Math.random() < GENTLE_CHANCE) return { ...guide, situation: 'gentle.wrong' }
const week = profile.week
+6
View File
@@ -179,6 +179,12 @@ export const MASCOT_LINES = {
'下次比赛,我押你',
'你是我最熟的同学……之一',
],
// 跨天记得的事(behavior.ts 的 memoryGuide):今天第一次在闲聊类情况点她时翻一次旧账,同一件事只翻一次。
// {when} 是「昨天」「前天」「前几天」
'memory.grudge': ['{when}把我惹生气的是你吧', '{when}的账还没算呢', '哼,{when}的事我还记着', '{when}戳到我背过身,忘了?'],
'memory.pat': ['{when}摸我头的账还没算', '别以为{when}摸头的事我忘了', '{when}是谁摸我头来着', '{when}头发被你弄乱了'],
// 今天好感升了一档:档位不显示,这句是唯一的暗示
'memory.closer': ['……最近跟你熟了一点', '你最近做了不少题嘛……我才没注意', '感觉跟你熟了点……错觉吧', '今天的你,好像比昨天顺眼'],
familiar: ['又是你', '你今天戳了几次了', '习惯了,戳吧', '老熟人了', '又来找我?'],
// ---- 接进来的其他数据 ----