This commit is contained in:
127
src/data/characterCombat.ts
Normal file
127
src/data/characterCombat.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
AnimationState,
|
||||
Character,
|
||||
CharacterAnimationConfig,
|
||||
CharacterSkillDefinition,
|
||||
CombatDelivery,
|
||||
SpriteSequenceDefinition,
|
||||
} from '../types';
|
||||
|
||||
const DEFAULT_FRAME_MS = 100;
|
||||
const DEFAULT_FPS = 10;
|
||||
|
||||
function getCharacterRoot(character: Character) {
|
||||
return `/character/${encodeURIComponent(character.assetFolder)}/${encodeURIComponent(character.assetVariant)}`;
|
||||
}
|
||||
|
||||
function buildFramesFromConfig(
|
||||
character: Character,
|
||||
config: CharacterAnimationConfig,
|
||||
folderPrefix = 'Hero',
|
||||
) {
|
||||
const normalizedBasePath = config.basePath?.replace(/\/+$/u, '');
|
||||
const extension = config.extension ?? 'png';
|
||||
|
||||
if (normalizedBasePath) {
|
||||
if (config.file) {
|
||||
return [`${normalizedBasePath}/${encodeURIComponent(config.file)}`];
|
||||
}
|
||||
|
||||
const frames: string[] = [];
|
||||
const startFrame = config.startFrame ?? 1;
|
||||
|
||||
for (let index = 0; index < config.frames; index += 1) {
|
||||
const frameNumber = (startFrame + index).toString().padStart(2, '0');
|
||||
frames.push(`${normalizedBasePath}/${config.prefix}${frameNumber}.${extension}`);
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
const root = getCharacterRoot(character);
|
||||
const folder = encodeURIComponent(config.folder);
|
||||
if (config.file) {
|
||||
return [`${root}/${folderPrefix}/${folder}/${encodeURIComponent(config.file)}`];
|
||||
}
|
||||
const frames: string[] = [];
|
||||
const startFrame = config.startFrame ?? 1;
|
||||
|
||||
for (let index = 0; index < config.frames; index += 1) {
|
||||
const frameNumber = (startFrame + index).toString().padStart(2, '0');
|
||||
frames.push(`${root}/${folderPrefix}/${folder}/${config.prefix}${frameNumber}.${extension}`);
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
function buildFramesFromAsset(
|
||||
character: Character,
|
||||
sequence: Extract<SpriteSequenceDefinition, { source: 'asset' }>,
|
||||
) {
|
||||
const root = getCharacterRoot(character);
|
||||
const folder = sequence.folder
|
||||
.split('/')
|
||||
.map(segment => encodeURIComponent(segment))
|
||||
.join('/');
|
||||
|
||||
if (sequence.file) {
|
||||
return [`${root}/${folder}/${encodeURIComponent(sequence.file)}`];
|
||||
}
|
||||
|
||||
const frames: string[] = [];
|
||||
const totalFrames = Math.max(1, sequence.frames ?? 1);
|
||||
const startFrame = sequence.startFrame ?? 1;
|
||||
const extension = sequence.extension ?? 'png';
|
||||
|
||||
for (let index = 0; index < totalFrames; index += 1) {
|
||||
const frameNumber = (startFrame + index).toString().padStart(2, '0');
|
||||
frames.push(`${root}/${folder}/${sequence.prefix ?? ''}${frameNumber}.${extension}`);
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
export function getCharacterAnimationConfig(
|
||||
character: Character,
|
||||
animation: AnimationState,
|
||||
) {
|
||||
return character.animationMap?.[animation] ?? null;
|
||||
}
|
||||
|
||||
export function getCharacterAnimationDurationMs(
|
||||
character: Character,
|
||||
animation: AnimationState,
|
||||
) {
|
||||
const config = getCharacterAnimationConfig(character, animation);
|
||||
if (!config) return DEFAULT_FRAME_MS;
|
||||
return Math.max(DEFAULT_FRAME_MS, config.frames * DEFAULT_FRAME_MS);
|
||||
}
|
||||
|
||||
export function getSequenceFps(sequence: SpriteSequenceDefinition) {
|
||||
return sequence.fps ?? DEFAULT_FPS;
|
||||
}
|
||||
|
||||
export function getSequenceDurationMs(sequence: SpriteSequenceDefinition, frameCount: number) {
|
||||
const fps = getSequenceFps(sequence);
|
||||
return Math.max(DEFAULT_FRAME_MS, Math.ceil((Math.max(1, frameCount) * 1000) / fps));
|
||||
}
|
||||
|
||||
export function resolveSequenceFrames(
|
||||
character: Character,
|
||||
sequence: SpriteSequenceDefinition,
|
||||
) {
|
||||
if (sequence.source === 'animation') {
|
||||
const config = getCharacterAnimationConfig(character, sequence.animation);
|
||||
return config ? buildFramesFromConfig(character, config) : [];
|
||||
}
|
||||
|
||||
return buildFramesFromAsset(character, sequence);
|
||||
}
|
||||
|
||||
export function getSkillCasterAnimation(skill: CharacterSkillDefinition) {
|
||||
return skill.casterAnimation ?? skill.animation;
|
||||
}
|
||||
|
||||
export function getSkillDelivery(skill: CharacterSkillDefinition): CombatDelivery {
|
||||
return skill.delivery ?? (skill.style === 'projectile' ? 'ranged' : 'melee');
|
||||
}
|
||||
Reference in New Issue
Block a user