52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
export type SkillConditionMember = {
|
|
type: string;
|
|
generation: string;
|
|
};
|
|
|
|
export function plainSkillText(value: string): string {
|
|
return value.replace(/\[[^\]]+\]/g, '').replace(/\s+/g, ' ').trim();
|
|
}
|
|
|
|
function normalizedGroup(value: string): string {
|
|
return value
|
|
.replace(/^hololive\s+/i, '')
|
|
.replace(/\(이\)가$/, '')
|
|
.replace(/\s*타입$/, '')
|
|
.trim()
|
|
.toLowerCase();
|
|
}
|
|
|
|
function memberBelongsTo(member: SkillConditionMember, group: string): boolean {
|
|
const normalized = normalizedGroup(group);
|
|
const type = normalizedGroup(member.type);
|
|
const generation = normalizedGroup(member.generation);
|
|
const generations = member.generation
|
|
.split('/')
|
|
.map((value) => normalizedGroup(value))
|
|
.filter(Boolean);
|
|
return type === normalized
|
|
|| generation === normalized
|
|
|| generation.endsWith(normalized)
|
|
|| generations.some((value) => value === normalized || value.endsWith(normalized));
|
|
}
|
|
|
|
export function skillConditionSatisfied(
|
|
condition: string,
|
|
members: readonly SkillConditionMember[]
|
|
): boolean {
|
|
const description = plainSkillText(condition);
|
|
if (!description) return true;
|
|
|
|
// 콤보와 라이프는 분석에서 최적 플레이를 전제로 항상 충족한다.
|
|
if (/\d+콤보 이상이면/.test(description) || /라이프 \d+ 이상이면/.test(description)) return true;
|
|
|
|
const deckCondition = description.match(/^(.+?)\s*(\d+)명 이상이면$/);
|
|
if (!deckCondition) return true;
|
|
const requiredCount = Number(deckCondition[2]);
|
|
return members.filter((member) => memberBelongsTo(member, deckCondition[1])).length >= requiredCount;
|
|
}
|
|
|
|
export function skillTargetBelongsTo(member: SkillConditionMember, group: string): boolean {
|
|
return memberBelongsTo(member, group);
|
|
}
|