import type { RoleRelationState } from '../types'; export type AffinityLevelId = | 'hostile' | 'guarded' | 'eased' | 'friendly' | 'trusted' | 'close'; export type AffinityLevelMeta = { id: AffinityLevelId; label: string; minAffinity: number; markerAffinity: number; nextAffinity: number | null; description: string; accentClassName: string; relationStance: RoleRelationState['stance']; }; export const AFFINITY_PROGRESS_MIN = -40; export const AFFINITY_PROGRESS_MAX = 90; export const AFFINITY_LEVELS: AffinityLevelMeta[] = [ { id: 'hostile', label: '敌对', minAffinity: Number.NEGATIVE_INFINITY, markerAffinity: AFFINITY_PROGRESS_MIN, nextAffinity: 0, description: '好感落入负值区间后,会按敌对关系处理,靠近时通常直接进入对战。', accentClassName: 'border-rose-300/28 bg-rose-500/14 text-rose-100', relationStance: 'hostile', }, { id: 'guarded', label: '戒备', minAffinity: 0, markerAffinity: 0, nextAffinity: 15, description: '对方仍保持明显距离,只会给出谨慎而有限的回应。', accentClassName: 'border-white/12 bg-white/8 text-zinc-100', relationStance: 'guarded', }, { id: 'eased', label: '缓和', minAffinity: 15, markerAffinity: 15, nextAffinity: 30, description: '戒备已经开始松动,愿意正常交流,也会试探性配合你的节奏。', accentClassName: 'border-sky-300/20 bg-sky-500/10 text-sky-100', relationStance: 'neutral', }, { id: 'friendly', label: '友善', minAffinity: 30, markerAffinity: 30, nextAffinity: 60, description: '态度明显友善了许多,愿意配合行动,也会给出更真诚的反馈。', accentClassName: 'border-emerald-300/20 bg-emerald-500/10 text-emerald-100', relationStance: 'cooperative', }, { id: 'trusted', label: '信任', minAffinity: 60, markerAffinity: 60, nextAffinity: 90, description: '双方已经建立稳定信任,对方更愿意分享想法、资源和立场。', accentClassName: 'border-amber-300/20 bg-amber-500/10 text-amber-100', relationStance: 'bonded', }, { id: 'close', label: '深交', minAffinity: 90, markerAffinity: 90, nextAffinity: null, description: '关系已经非常亲近,对方几乎把你视作可以托付后背的自己人。', accentClassName: 'border-rose-300/22 bg-rose-500/12 text-rose-100', relationStance: 'bonded', }, ]; export const DEFAULT_AFFINITY_LEVEL = AFFINITY_LEVELS[0]!; export const AFFINITY_PROGRESS_MARKERS = AFFINITY_LEVELS.map((level) => ({ value: level.markerAffinity, label: level.label, })); export const AFFINITY_BACKSTORY_CHAPTER_THRESHOLDS = [ getAffinityLevelMetaById('eased').minAffinity, getAffinityLevelMetaById('friendly').minAffinity, getAffinityLevelMetaById('trusted').minAffinity, getAffinityLevelMetaById('close').minAffinity, ] as const satisfies readonly [number, number, number, number]; export const DEFAULT_PRIVATE_CHAT_UNLOCK_AFFINITY = getAffinityLevelMetaById('trusted').minAffinity; export function getAffinityLevelMetaById(levelId: AffinityLevelId) { const level = AFFINITY_LEVELS.find((entry) => entry.id === levelId); if (!level) { throw new Error(`Unknown affinity level id: ${levelId}`); } return level; } export function getAffinityLevelMeta(affinity: number) { return ( [...AFFINITY_LEVELS] .reverse() .find((level) => affinity >= level.minAffinity) ?? DEFAULT_AFFINITY_LEVEL ); } export function resolveRelationStanceFromAffinity( affinity: number, ): RoleRelationState['stance'] { return getAffinityLevelMeta(affinity).relationStance; }