131 lines
3.7 KiB
TypeScript
131 lines
3.7 KiB
TypeScript
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;
|
|
}
|