import type { ActionId } from '../shared/types.js';
import { COSMETIC_COLORS, SKIN_TONES, type EquipmentId } from '../../constants/cosmetics.js';
import { normalizeAppearance, type FighterAppearance } from '../shared/cosmetics.js';
function equipped(appearance: FighterAppearance | undefined, item: EquipmentId) {
return !appearance || !!appearance.equipment?.includes(item);
}
function fighterPalette(index: number, appearance?: FighterAppearance) {
const palette = (appearance?.characterId ?? index) === 1
? '--skin:#b59173;--skin-shade:#786650;--skin-light:#dcc0a0;--suit:#455862;--suit-dark:#293840;--trim:#d7d5bf;--hair:#d7d9cf;--hair-shadow:#7e8d90'
: '--skin:#d7ad8a;--skin-shade:#996b55;--skin-light:#f0cdaa;--suit:#aa5740;--suit-dark:#613b33;--trim:#d3bf99;--hair:#242b30;--hair-shadow:#454e53';
if (!appearance) return palette;
const selected = normalizeAppearance(appearance);
const color = COSMETIC_COLORS.find(color => color.id === selected.colorId) ?? COSMETIC_COLORS[0];
const skin = SKIN_TONES.find(tone => tone.id === selected.skinTone) ?? SKIN_TONES[0];
return palette
.replace(/--skin:[^;]+;--skin-shade:[^;]+;--skin-light:[^;]+;/,
`--skin:${skin.skin};--skin-shade:${skin.shade};--skin-light:${skin.light};`)
.replace(/--suit:[^;]+;--suit-dark:[^;]+;--trim:[^;]+;/,
`--suit:${color.suit};--suit-dark:${color.suitDark};--trim:${color.trim};`)
.replace(/--hair:[^;]+;--hair-shadow:[^;]+/,
selected.hairStyle === 'white' ? '--hair:#d7d9cf;--hair-shadow:#7e8d90' : '--hair:#242b30;--hair-shadow:#454e53');
}
/** Shared head drawing: full-body art and the hit close-up always depict the same fighter. */
function fighterHead(index: number, includeNeck = true, appearance?: FighterAppearance) {
const veteran = index === 1;
const hairStyle = appearance ? normalizeAppearance(appearance).hairStyle : veteran ? 'white' : 'black';
const bald = hairStyle === 'bald', whiteHair = hairStyle === 'white';
const headband = appearance ? equipped(appearance, 'headband') : !veteran;
const eyewear = appearance?.equipment?.includes('sunglasses') ? 'sunglasses'
: appearance?.equipment?.includes('glasses') ? 'glasses' : undefined;
return `
${bald ? '' : whiteHair ? '' : ''}
${includeNeck ? '\n ' : ''}
${bald ? '' : ''}
${bald ? '' : whiteHair ? '' : ''}
${veteran ? '' : ''}
${headband ? '' : ''}
${eyewear ? `
` : ''}
`;
}
/** Athletic ink-and-cel figures retain the arena's existing 260 × 300 geometry. */
export function fighterArt(index: number, closeup = false, appearance?: FighterAppearance) {
const characterId = appearance?.characterId ?? index;
const veteran = characterId === 1;
const shoes = equipped(appearance, 'shoes'), wristbands = equipped(appearance, 'wristbands');
return ``;
}
/** Preserved Yamcha-reference variant; not used by the active finisher. */
export function yamchaFallenFighterArt(index: number) {
return ``;
}
/** Slumped against a rock face, with loose arms and legs extending along the ground. */
function fallenFighterArt(index: number, appearance?: FighterAppearance) {
const characterId = appearance?.characterId ?? index;
const shoes = equipped(appearance, 'shoes'), wristbands = equipped(appearance, 'wristbands');
return ``;
}
function beamFinisherArt(hitIndex: 0 | 1, appearances?: [FighterAppearance, FighterAppearance]) {
const attacker = 1 - hitIndex;
const victim = appearances?.[hitIndex];
const maskId = `beam-remnant-${hitIndex}`;
const reactionMaskId = `beam-reaction-${hitIndex}`;
return `
${fighterArt(attacker, true, appearances?.[attacker])}
${fighterArt(hitIndex, false, appearances?.[hitIndex])}
${fighterArt(attacker, false, appearances?.[attacker])}
`;
}
export function finisherArt(hitIndex: 0 | 1, attack: ActionId, appearances?: [FighterAppearance, FighterAppearance]) {
if (attack === 'beam') return beamFinisherArt(hitIndex, appearances);
const attacker = 1 - hitIndex;
const speedLines = Array.from({ length: 44 }, (_, i) => {
const angle = i * Math.PI / 22, inner = 85 + (i % 4) * 21;
const x = (r: number) => (400 + Math.cos(angle) * r).toFixed(1);
const y = (r: number) => (170 + Math.sin(angle) * r * .65).toFixed(1);
return ``;
}).join('');
return `
${fighterArt(attacker, true, appearances?.[attacker])}
${[0, 1].map(index => `
${fighterArt(index, false, appearances?.[index])}
`).join('')}
쾅!
${fallenFighterArt(hitIndex, appearances?.[hitIndex])}
`;
}
export function ashPileArt() {
return ``;
}
export function actionIcon(action: ActionId) {
const shapes: Record = {
charge: '',
blast: '',
guard: '',
beam: '',
dodge: '',
};
return ``;
}
export const checkIcon = '';