import { TableNames } from '../../game/ConfigTableData'; import type { SkillPresentationContext } from './SkillPresentationTypes'; export interface AtkTypeParts { head: number; param: number; } export interface WuSpinSkillParts { secPerRev: number; stickCount: number; volumeCells: number; durationSec: number; damageScale: number; } export interface WheelSkillParts { secPerRev: number; count: number; volume: number; radiusPx: number; damageScale: number; } export function parseAtkTypeString(raw: string): AtkTypeParts | null { const t = String(raw ?? '').trim(); if (!t || t === '0') return null; const parts = t.split(',').map(Number); const head = parts[0]; if (!Number.isFinite(head)) return null; const param = parts.length >= 2 && Number.isFinite(parts[1]) ? parts[1] : 0; return { head, param }; } export function readBaseAtkRow(baseAtkId: number): ITableSkill | null { if (baseAtkId <= 0) return null; return gg.data.table.getTableData(TableNames.Skill, baseAtkId) ?? null; } export function readAtkTypeParamFromBaseAtkId( baseAtkId: number, expectedHead?: number, ): number | null { const row = readBaseAtkRow(baseAtkId); if (!row) return null; const parsed = parseAtkTypeString(row.atk_type); if (!parsed) return null; if (expectedHead != null && parsed.head !== expectedHead) return null; return parsed.param > 0 ? parsed.param : null; } export function resolvePresentationAtkTypeParam( ctx: Pick, expectedHead?: number, ): number | null { const fromParam = Number(ctx.params.atkTypeParam); if (Number.isFinite(fromParam) && fromParam > 0) return fromParam; return readAtkTypeParamFromBaseAtkId(ctx.baseAtkId, expectedHead); } export function requirePart(parts: readonly number[], index: number): number | null { if (index < 0 || index >= parts.length) return null; const v = Number(parts[index]); return Number.isFinite(v) ? v : null; } export function requirePositivePart(parts: readonly number[], index: number): number | null { const v = requirePart(parts, index); return v != null && v > 0 ? v : null; } export function requireNonNegativePart(parts: readonly number[], index: number): number | null { const v = requirePart(parts, index); return v != null && v >= 0 ? v : null; } export function parseSkillParts(params: Readonly>): number[] | null { const rawParts = params.skillParts as number[] | undefined; if (rawParts?.length) return [...rawParts]; const raw = String(params.skillRaw ?? '').trim(); if (!raw) return null; const parts = raw.split(',').map(Number); return parts.some((n) => !Number.isFinite(n)) ? null : parts; } export function parseWuSpinSkillParts(parts: readonly number[]): WuSpinSkillParts | null { if ((parts[0] ?? 0) !== 1 || parts.length < 5) return null; const secPerRev = requirePositivePart(parts, 1); const stickCountRaw = requirePart(parts, 2); const volumeCells = requirePositivePart(parts, 3); const durationSec = requirePositivePart(parts, 4); if (secPerRev == null || stickCountRaw == null || volumeCells == null || durationSec == null) { return null; } const stickCount = Math.floor(stickCountRaw); if (stickCount < 1) return null; const damageScale = parts.length >= 6 ? requirePositivePart(parts, 5) : requirePositivePart(parts, parts.length - 1); if (damageScale == null) return null; return { secPerRev, stickCount, volumeCells, durationSec, damageScale }; } export function parseWheelSkillParts(parts: readonly number[]): WheelSkillParts | null { if ((parts[0] ?? 0) !== 7 || parts.length < 6) return null; const secPerRev = requirePositivePart(parts, 1); const countRaw = requirePart(parts, 2); const volume = requirePositivePart(parts, 3); const radiusPx = requirePositivePart(parts, 4); const damageScale = requirePositivePart(parts, 5); if (secPerRev == null || countRaw == null || volume == null || radiusPx == null || damageScale == null) { return null; } const count = Math.floor(countRaw); if (count < 1) return null; return { secPerRev, count, volume, radiusPx, damageScale }; } export function parseSkill2RadiusParts( parts: readonly number[], rangeAdd = 0, ): { radiusPx: number; damageScale: number } | null { if ((parts[0] ?? 0) !== 2 || parts.length < 3) return null; const radiusBase = requirePositivePart(parts, 1); const damageScale = requirePositivePart(parts, 2); if (radiusBase == null || damageScale == null) return null; return { radiusPx: radiusBase + rangeAdd, damageScale }; } export function parseSkill5AreaParts(parts: readonly number[]): { radiusPx: number; scale: number; intervalSec: number; durationSec: number; } | null { if ((parts[0] ?? 0) !== 5 || parts.length < 5) return null; const radiusPx = requirePositivePart(parts, 1); const scale = requirePositivePart(parts, 2); const intervalSec = requirePositivePart(parts, 3); const durationSec = requirePositivePart(parts, 4); if (radiusPx == null || scale == null || intervalSec == null || durationSec == null) return null; return { radiusPx, scale, intervalSec, durationSec }; } export function parseSkill6BeamParts(parts: readonly number[]): { scale: number; intervalSec: number; durationSec: number; } | null { if ((parts[0] ?? 0) !== 6 || parts.length < 4) return null; const scale = requirePositivePart(parts, 1); const intervalSec = requirePositivePart(parts, 2); const durationSec = requirePositivePart(parts, 3); if (scale == null || intervalSec == null || durationSec == null) return null; return { scale, intervalSec, durationSec }; }