import { resolveRoleCombatStats } from '../data/attributeCombat'; import { getAttributeSlotValue } from '../data/attributeResolver'; import { type BuildDamageBreakdown, formatBuildContributionPercent, getBuildContributionQualityLabel, } from '../data/buildDamage'; import { getResourceLabelsForWorld } from '../services/customWorldPresentation'; import type { Character, RoleAttributeProfile, WorldAttributeSchema, } from '../types'; import { type ContributionRow, formatAttributeMetricValue, getAttributeBonusPillClassName, getAttributeEffectText, getContributionVisualStyle, getSkillDeliveryLabel, getSkillStyleLabel, } from './CharacterInfoHelpers'; export function StatusRow({ label, current, max, tone, }: { label: string; current: number; max: number; tone: 'hp' | 'mp'; }) { const ratio = Math.max(0, Math.min(1, max > 0 ? current / max : 0)); const fillClass = tone === 'hp' ? 'from-emerald-400 via-lime-300 to-emerald-200' : 'from-sky-500 via-cyan-300 to-sky-100'; return (
{label} {current} / {max}
); } export function CharacterSkillsList({ skills, onSelectSkill, emptyText = '暂无技能信息', }: { skills: Character['skills']; onSelectSkill?: ((skillId: string) => void) | null; emptyText?: string; }) { if (skills.length === 0) { return (
{emptyText}
); } return (
{skills.map((skill) => { const content = ( <>
{skill.name}
{getSkillDeliveryLabel(skill)}
伤害:{skill.damage}
法力:{skill.manaCost}
冷却:{skill.cooldownTurns}
距离:{skill.range}
{getSkillStyleLabel(skill)}
); if (onSelectSkill) { return ( ); } return (
{content}
); })}
); } export function MultiplierContributionList({ breakdown, onSelectContribution, }: { breakdown: BuildDamageBreakdown; onSelectContribution: (row: ContributionRow) => void; }) { const sortedRows = [...breakdown.rows].sort( (left, right) => right.bonusDelta - left.bonusDelta || left.label.localeCompare(right.label, 'zh-CN'), ); return (
状态标签 点击标签查看具体属性加成
{sortedRows.length > 0 ? (
{sortedRows.map((row) => ( ))}
) : ( 当前还没有形成有效标签 )}
); } export function CharacterAttributeGrid({ attributeProfile, attributeSchema, buildBreakdown = null, resourceLabels, emptyText = '暂无属性信息', gridClassName = 'grid grid-cols-1 gap-2 text-sm text-zinc-300 sm:grid-cols-2', cardClassName = 'rounded-xl border border-white/8 bg-black/25 px-3 py-2', }: { attributeProfile: RoleAttributeProfile | null | undefined; attributeSchema: WorldAttributeSchema; buildBreakdown?: BuildDamageBreakdown | null; resourceLabels: ReturnType; emptyText?: string; gridClassName?: string; cardClassName?: string; }) { const attributeRows = attributeSchema.slots.map((slot) => ({ slot, value: getAttributeSlotValue(attributeProfile, slot.slotId), })); const attributeBonusBySlot = Object.fromEntries( attributeSchema.slots.map((slot) => [ slot.slotId, Number( ( buildBreakdown?.rows.reduce( (sum, row) => sum + (row.attributeModifierDeltas?.[slot.slotId] ?? 0), 0, ) ?? 0 ).toFixed(4), ), ]), ) as Record; const boostedAttributeProfile = attributeProfile ? { ...attributeProfile, values: { ...(attributeProfile.values ?? {}), ...Object.fromEntries( attributeSchema.slots.map((slot) => { const baseValue = attributeProfile.values?.[slot.slotId] ?? 0; const totalBonus = attributeBonusBySlot[slot.slotId] ?? 0; return [ slot.slotId, Number((baseValue * (1 + totalBonus)).toFixed(4)), ]; }), ), }, } : null; const boostedCombatStats = boostedAttributeProfile ? resolveRoleCombatStats(boostedAttributeProfile) : null; const displayRows = attributeRows.map(({ slot, value }) => { const totalBonus = attributeBonusBySlot[slot.slotId] ?? 0; const boostedValue = Number((value * (1 + totalBonus)).toFixed(4)); return { slot, baseValue: value, boostedValue, totalBonus, effectText: boostedCombatStats ? getAttributeEffectText( slot.slotId, boostedCombatStats, resourceLabels, ) : slot.combatUseText, }; }); if (displayRows.length === 0) { return
{emptyText}
; } return (
{displayRows.map( ({ slot, baseValue, boostedValue, totalBonus, effectText }) => (
{slot.name}
{formatAttributeMetricValue(boostedValue)}
标签加成 {formatBuildContributionPercent(totalBonus)}
原始 {formatAttributeMetricValue(baseValue)}
{effectText}
), )}
); }